iOS实现日历翻页动画

本文我主要描述两方面:

1.日历(简单描述原理)

2.翻页动画(重点)

最终的效果如下图:

    图中沿四个对角的翻页动画,代表对应方向手势的滑动

1. 日历

要实现一个日历,其实原理很简单,我们只要知道三个数据:

1.今天是哪一天

2.这个月的第一天是星期几(哪天)

3.这个月总共有多少天

根据这个三个数据,就可以把得到的日期显示在日历上了,至于日历用什么来显示,我个人比较喜欢用UICollectionView,一个cell代表一天,当然也可以用很多个labelbutton来显示。

1.获取今天是哪一天

这个应该是最简单的: NSDate() , 就可以获取当前的日期

2.获取这个月的第一天是星期几(哪天)

下面的方法都是作为NSDateextension扩展的

//当前月第一天
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等,就可以得到想要的动画,CATransitiontype代表的是过渡时候的动画效果,subType一般代表动画的方向,但是查看了一下CATransitiontype属性,官方文档里面只描述了下面四种预定义的转场动画效果:

NSString * const kCATransitionFade;
NSString * const kCATransitionMoveIn;
NSString * const kCATransitionPush;
NSString * const kCATransitionReveal;

我们需要的翻页动画并不在里面,在google了一下之后,找到了一个比较理想的效果,通过直接设置CATransitiontype为"pageCurl"或"pangeUnCurl"进行动画,这两个值官方文档没有提供,我也不知道为啥这些大神能找到。。。

但是默认的朝上翻页只有左上角方向的动画,朝下翻页只有右下角方向的动画

做出来的效果如下图:

无法达到四个对角都能进行翻页动画的效果。

为了得到可以沿着四个对角方向翻页的效果,我们可以先在最底部添加一个containerView,然后在containerView中添加dayView(下面提到的dayView和代码中的dayView都代表的是作为日历的collectionView)。

如果要进行朝右上角翻页,我们只要把containerViewlayer先沿y轴翻转M_PI,这样,最开始的右下角就变成左下角了,翻页时就会变成向右上角翻页

但是为了日历显示正确,我们需要把dayViewlayer重新翻转过来,这样,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动画的时候能有所帮助。

(0)

相关推荐

  • iOS My97DatePicker日历使用详解

    一.效果图 二.工程图 三.代码 RootViewController.h #import <UIKit/UIKit.h> @interface RootViewController : UIViewController @end RootViewController.m #import "RootViewController.h" //加入头文件 #import "My97DatePicker.h" @interface RootViewControl

  • iOS Swift开发之日历插件开发示例

    本文介绍了iOS Swift开发之日历插件开发示例,分享给大家,具体如下: 效果图 0x01 如何获取目前日期 关于日期,苹果给出了 Date 类,初始化一个 Date 类 let date = Date() 打印出来就是当前系统的日期和时间 那么如何单独获得当前年份,月份呢? var date: [Int] = [] let calendar: Calendar = Calendar(identifier: .gregorian) var comps: DateComponents = Dat

  • iOS实现一个简易日历代码

    日历一般都是用UICollectionView进行开发的,相关demo也很多,这里就讲一个我最近写的玩的demo,由于时间原因没来得及加年历和周历,一个月历的小demo,随着月份天数的不同,自动改变日历的高. 代理部分: @protocol KJCalendarDelegate <NSObject> /** 随着每个月的天数不一样而改变高度 @param height 日历高度 */ - (void)calendarViewHeightChange:(CGFloat)height; /** 当

  • iOS自定义日历控件的简单实现过程

    因为程序要求要插入一个日历控件,该空间的要求是从当天开始及以后的六个月内的日历,上网查资料基本上都说只要获取两个条件(当月第一天周几和本月一共有多少天)就可以实现一个简单的日历,剩下的靠自己的简单逻辑就OK了,下面开始自己从开始到完成的整个过程 1.首先做NSDate类目,扩展一些方法让日期之间转换更加方便 #import <Foundation/Foundation.h> @interface NSDate (LYWCalendar) #pragma mark - 获取日 - (NSInte

  • iOS实现日历翻页动画

    本文我主要描述两方面: 1.日历(简单描述原理) 2.翻页动画(重点) 最终的效果如下图:     图中沿四个对角的翻页动画,代表对应方向手势的滑动 1. 日历 要实现一个日历,其实原理很简单,我们只要知道三个数据: 1.今天是哪一天 2.这个月的第一天是星期几(哪天) 3.这个月总共有多少天 根据这个三个数据,就可以把得到的日期显示在日历上了,至于日历用什么来显示,我个人比较喜欢用UICollectionView,一个cell代表一天,当然也可以用很多个label,button来显示. 1.获

  • jquery带翻页动画的电子杂志代码分享

    这是一款基于jquery实现的带翻页动画的电子杂志,小编有时就在想我们读的纸质课本可不可以都改成电子书,这要是不是会更节省资源呐? 记得以前我们有介绍过不少书本翻页的动画,比如这款CSS3书本翻页动画,制作就非常逼真.今天要分享的这款jQuery书本翻页3D动画功能更加强大,可以支持任意数量页的翻阅,并且也有非常美观的视觉效果.书本的内容支持任意HTML元素,相当灵活. 运行效果图                         --------------------------------查

  • Android 仿日历翻页、仿htc时钟翻页、数字翻页切换效果

    废话不多说,效果图: 自定义控件找自网络,使用相对简单,具体还没有来得及深入研究,只是先用笨方法大概实现了想要的效果,后续有空会仔细研究再更新文章, 本demo切换方法是用的笨方法,也就是由新数字和旧数字相比较来切换数字变换的,大致使用方法如下: //获取输入框中的数字 int newNumber = Integer.parseInt(etInput.getText().toString()); //获取个.十.百位数字 int nbai = newNumber / 100; int nshi

  • Android CardView+ViewPager实现ViewPager翻页动画的方法

    Viewpager通俗一点讲就是一个允许左右翻转带数据的页面的布局管理器,经常用来连接Fragment,它很方便管理每个页面的生命周期,使用ViewPager管理Fragment是标准的适配器实现.最常用的实现一般有FragmentPagerAdapter和FragmentStatePagerAdapter.自行百度它的用法.今天我们要实现的是下面的效果: NO PICTURE TALK A JB 要实现图中的效果需要以下几个知识点: 1.clipChildren属性 2.一个页面显示多个Vie

  • vue+animation实现翻页动画

    本文实例为大家分享了vue+animation实现翻页动画展示的具体代码,供大家参考,具体内容如下 前端在做数据展示的时候,可能提留页面时间较长,导致数据不能及时更新,你可以定时更新,也可以做一个假数据 给用户视觉上的体验,接下来就是第二种,假数据,它用了C3 animation 实现了一个翻页动画. 第一种是单独运动 <template> <div> <div> <ul> <li v-for="(item,i) in NumberList&

  • vue实现数字翻页动画

    本文实例为大家分享了vue实现数字翻页动画的具体代码,供大家参考,具体内容如下 一.看效果 二.实现步骤 1.新建翻页组件scrollNumber.vue <template>     <div class="count-flop" :key="compKey">         <div :class="item != '.' && item != ',' ?'count-flop-box':'count-f

  • jquery+css3问卷答题卡翻页动画效果示例

    CSS3+jQuery制作立体翻页时间展示动画特效.该翻页插件的外观非常华丽喜庆,非常适合产品活动或者育儿网站使用. 这个选项调查的特效以选项卡的形式,每答完一道题目自动切换到下一条,颇具特色.使用jQuery和CSS3,适合HTML5浏览器. 代码如下: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatib

  • vue实现书本翻页动画效果实例详解

    偶然兴起,想要用vue来做一个书本的组件,有了这个想法后边开始动手,先简单地实现基本的效果,为后续封装为组件进行准备工作,实现该效果的要使用vue + css + JavaScript. 关键字 transform Transform属性应用于元素的2D或3D转换.这个属性允许你将元素旋转,缩放,移动,倾斜等. 语法为transform: none|*transform-functions*; 我们主要使用到其旋转效果,我们可以这样写. transform: rotateY(90deg) //表

  • iOS图片界面翻页切换效果

    先看效果: 下面贴代码: #import "ViewController.h" @interface ViewController () @property (weak, nonatomic) IBOutlet UIImageView *backgroundView; @property (strong,nonatomic) NSArray *array; @end @implementation ViewController -(NSArray *)array { if (_arra

  • ios电子书翻页效果代码详解

    近实现了一个完整的电子书阅读器,支持txt和epub格式的电子书阅读,其中epub支持图文混排的方式展示.本文主要谈谈其中两种翻页效果的实现,分别为仿真翻页和水平滑动翻页. 仿真翻页 最合适的方案就是使用系统提供的UIPageviewcontroller了,不过默认的UIpageviewcontroller翻页时背面是白色的,而阅读器通常都会有背景色或背景图片,翻页时用户体验就很糟糕,比如就像下面这样 所以接下来主要说说如何修改背面颜色以达到美观的翻页效果. UIpageviewcontroll

随机推荐