本文我主要描述两方面:
1.日历(简单描述原理)
2.翻页动画(重点)
最终的效果如下图:
图中沿四个对角的翻页动画,代表对应方向手势的滑动
1. 日历
要实现一个日历,其实原理很简单,我们只要知道三个数据:
1.今天是哪一天
2.这个月的第一天是星期几(哪天)
3.这个月总共有多少天
根据这个三个数据,就可以把得到的日期显示在日历上了,至于日历用什么来显示,我个人比较喜欢用UICollectionView,一个cell代表一天,当然也可以用很多个label,button来显示。
1.获取今天是哪一天
这个应该是最简单的: NSDate() , 就可以获取当前的日期
2.获取这个月的第一天是星期几(哪天)
下面的方法都是作为NSDate的extension扩展的
//当前月第一天 func firstDateOfCurrentMonth() ->NSDate{ let calendar = NSCalendar(identifier:NSCalendarIdentifierGregorian ) let currentDateComponents = calendar!.components([.Year,.Month], fromDate: self) let startOfMonth = calendar!.dateFromComponents(currentDateComponents) let date = startOfMonth?.dateByAddingTimeInterval(8*60*60) return date! } //当前月的第一天是星期几 func firstDayOfCurrentMonth() -> Int { let calendar = NSCalendar.currentCalendar() let components = calendar.components(.Weekday, fromDate: firstDateOfCurrentMonth()) return components.weekday-1 }
3.获取这个月总共有多少天
根绝上面这些数据,就可以得到日历里面每个格子应该显示的日期,具体的显示和有关日期的三个主要的类: NSDate, NSCalendar, NSDateComponents 由于不是本文的重点,我这里就不详细说了,如果有不明白的可以去看一下文档,或者如果我下次写一个详细的关于这三个类的(又挖一个坑。。)。
2. 翻页动画
动画思路:
上面的动画属于转场动画的一种,所以我们可以利用CATrasition进行动画,CATransition的使用非常简单,只要设置动画时长,时间函数,fillMode等,就可以得到想要的动画,CATransition的type代表的是过渡时候的动画效果,subType一般代表动画的方向,但是查看了一下CATransition的type属性,官方文档里面只描述了下面四种预定义的转场动画效果:
NSString * const kCATransitionFade; NSString * const kCATransitionMoveIn; NSString * const kCATransitionPush; NSString * const kCATransitionReveal;
我们需要的翻页动画并不在里面,在google了一下之后,找到了一个比较理想的效果,通过直接设置CATransition的type为"pageCurl"或"pangeUnCurl"进行动画,这两个值官方文档没有提供,我也不知道为啥这些大神能找到。。。
但是默认的朝上翻页只有左上角方向的动画,朝下翻页只有右下角方向的动画
做出来的效果如下图:
无法达到四个对角都能进行翻页动画的效果。
为了得到可以沿着四个对角方向翻页的效果,我们可以先在最底部添加一个containerView,然后在containerView中添加dayView(下面提到的dayView和代码中的dayView都代表的是作为日历的collectionView)。
如果要进行朝右上角翻页,我们只要把containerView的layer先沿y轴翻转M_PI,这样,最开始的右下角就变成左下角了,翻页时就会变成向右上角翻页
但是为了日历显示正确,我们需要把dayView的layer重新翻转过来,这样,containerView是反的,但是我们看到的日期显示是正的
左下角翻页也是同样的道理。
具体代码如下:
//为dayView(代表日历的collectionview)添加一个滑动手势 func addPanGestureToDayView() { let swipe = UIPanGestureRecognizer(target: self, action: #selector(self.panOnDayView(_:))) dayView.addGestureRecognizer(swipe) } //当在dayView上滑动时触发 func panOnDayView(pan: UIPanGestureRecognizer) { //如果手势的状态是结束状态 //或者当前动画已经结束(防止上一个翻页动画还没结束,就开始下一个) //添加翻页的转场动画到dayView上 if pan.state == .Ended && !animatiing{ addAnimationToDayView(pan) } } let pageCurlDuration = 0.5 //动画时间 let kPageCurlKey = "pageCurl" //往上翻页的的type let kPageUnCurlKey = "pageUnCurl" //往下翻页的type //添加动画到日历 func addAnimationToDayView(pan: UIPanGestureRecognizer) { let translation = pan.translationInView(dayView) //创建一个转场动画 let transitioin = CATransition() transitioin.duration = pageCurlDuration transitioin.timingFunction = CAMediaTimingFunction(name: "default") //在动画结束之后保证状态不被移除(这个两个属性得同时设置) transitioin.fillMode = kCAFillModeForwards transitioin.removedOnCompletion = false //设置代理,在动画开始和结束的代理方法中可以处理一些事情 transitioin.delegate = self if translation.y < 0 {//手势向上 * * if translation.x > 0 {//手势朝右上角滑动,朝右上翻页 //沿y轴对containerView进行M_PI角度翻转,使containerView的右下角变为左下角 animationContainerView.layer.transform = CATransform3DMakeRotation(CGFloat(M_PI), 0, 1, 0) //因为dayView是加在containerView上面的,如果不把dayView重新翻转回去,显示出来的界面都是反的 dayView.layer.transform = CATransform3DMakeRotation(CGFloat(-M_PI), 0, 1, 0) } //转场动画的效果 transitioin.type = kPageCurlKey //转场动画方向 transitioin.subtype = kCATransitionFromBottom //设置一个month的key,为了在动画结束时判断动画代表的是上一个月,还是下一个月 transitioin.setValue("next", forKey: "month") }else{//下 if translation.x < 0 {//手势朝左下角滑动,朝左下翻页 animationContainerView.layer.transform = CATransform3DMakeRotation(CGFloat(M_PI), 0, 1, 0) dayView.layer.transform = CATransform3DMakeRotation(CGFloat(-M_PI), 0, 1, 0) } transitioin.type = kPageUnCurlKey transitioin.subtype = kCATransitionFromTop transitioin.setValue("pre", forKey: "month") } dayView.layer.addAnimation(transitioin, forKey: "pageCurl") }
动画开始和停止时,进行一些处理:
//因为上面设置了 transitioin.delegate = self,这两个代理方法会自动调用 override func animationDidStart(anim: CAAnimation) { //动画开始时,判断当前动画是代表往上翻页,还是往下翻页,来刷新日历时间 animatiing = true let components = GregorianCalendar?.components([.Year,.Month,.Day], fromDate: date) if anim.valueForKey("month") as! String == "next" { components?.month += 1 }else if anim.valueForKey("month") as! String == "pre"{ components?.month -= 1 } date = (GregorianCalendar?.dateFromComponents(components!))! dateDidChaged!(date: date) } //动画结束时,将layer的transform属性设置为初始值,并移除dayView的layer上翻页的动画 override func animationDidStop(anim: CAAnimation, finished flag: Bool) { if flag { animatiing = false animationContainerView.layer.transform = CATransform3DIdentity dayView.layer.transform = CATransform3DIdentity dayView.layer.removeAnimationForKey("pageCurl") } }
总结:
这篇文章没有介绍太多详细的内容,其实翻页的动画实现还有别的方法,但是因为我想实现的是可以沿着四个对角进行动画的效果,所以最终选择了这个方法,上面说的好像不是很具体,如果不是很明白,可以先查看一下CATranstion的使用方法。以上就是本文的全部内容,希望对大家开发IOS动画的时候能有所帮助。
实现类似91熊猫看书的电子书翻页效果。可以随着手指的滑动进行翻页。 [Code4App.com]
本文向大家介绍Android 仿日历翻页、仿htc时钟翻页、数字翻页切换效果,包括了Android 仿日历翻页、仿htc时钟翻页、数字翻页切换效果的使用技巧和注意事项,需要的朋友参考一下 废话不多说,效果图: 自定义控件找自网络,使用相对简单,具体还没有来得及深入研究,只是先用笨方法大概实现了想要的效果,后续有空会仔细研究再更新文章, 本demo切换方法是用的笨方法,也就是由新数字和旧数字相比
本文向大家介绍Android实现页面翻转和自动翻转功能,包括了Android实现页面翻转和自动翻转功能的使用技巧和注意事项,需要的朋友参考一下 1. 效果图,本功能用了ViewFlipper和GestureDetector (手势检测器)两个关键技术点: 2. 先写好布局文件,这里用到了ViewFlipper类,用于切换视图,毕竟ViewFlipper见得少,先介绍一下。 在xml布局中的方法介绍
本文向大家介绍Bootstrap实现翻页效果,包括了Bootstrap实现翻页效果的使用技巧和注意事项,需要的朋友参考一下 Bootstrap之翻页。 优点: 支持局部刷新; 只要是列表,都可以加载该组件; 支持动态数据绑定; 当然还有绝对的简单实用。 效果图 最后一页时: 最开始一页时: 实现 ①、翻页组件的布局 pageNum:第几页 rel:要刷新哪一个div的id urlParas:其他参
本文向大家介绍Android CardView+ViewPager实现ViewPager翻页动画的方法,包括了Android CardView+ViewPager实现ViewPager翻页动画的方法的使用技巧和注意事项,需要的朋友参考一下 Viewpager通俗一点讲就是一个允许左右翻转带数据的页面的布局管理器,经常用来连接Fragment,它很方便管理每个页面的生命周期,使用ViewPager管
本文向大家介绍Android ViewPager实现左右滑动翻页效果,包括了Android ViewPager实现左右滑动翻页效果的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了ViewPager实现左右滑动翻页效果展示的具体代码,供大家参考,具体内容如下 代码如下: 布局文件: 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持呐喊教程。