服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - IOS - iOS实现日历翻页动画

iOS实现日历翻页动画

2021-01-23 16:33iOS开发网 IOS

本文的内容主要是在IOS中实现日历翻页的动画,界面简单但效果很好,以后可以运用到app中,下面一起来看看。

本文我主要描述两方面:

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

    2.翻页动画(重点)

最终的效果如下图:

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

iOS实现日历翻页动画

1. 日历

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

    1.今天是哪一天

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

    3.这个月总共有多少天

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

1.获取今天是哪一天

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

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//当前月第一天
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属性,官方文档里面只描述了下面四种预定义的转场动画效果:

?
1
2
3
4
nsstring * const kcatransitionfade;
nsstring * const kcatransitionmovein;
nsstring * const kcatransitionpush;
nsstring * const kcatransitionreveal;

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

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

做出来的效果如下图:

iOS实现日历翻页动画

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

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

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

但是为了日历显示正确,我们需要把dayviewlayer重新翻转过来,这样,containerview是反的,但是我们看到的日期显示是正的

左下角翻页也是同样的道理。

具体代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
//为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")
}

动画开始和停止时,进行一些处理:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//因为上面设置了 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动画的时候能有所帮助。

延伸 · 阅读

精彩推荐
  • IOSiOS 雷达效果实例详解

    iOS 雷达效果实例详解

    这篇文章主要介绍了iOS 雷达效果实例详解的相关资料,需要的朋友可以参考下...

    SimpleWorld11022021-01-28
  • IOSIOS 屏幕适配方案实现缩放window的示例代码

    IOS 屏幕适配方案实现缩放window的示例代码

    这篇文章主要介绍了IOS 屏幕适配方案实现缩放window的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要...

    xiari5772021-06-01
  • IOSiOS布局渲染之UIView方法的调用时机详解

    iOS布局渲染之UIView方法的调用时机详解

    在你刚开始开发 iOS 应用时,最难避免或者是调试的就是和布局相关的问题,下面这篇文章主要给大家介绍了关于iOS布局渲染之UIView方法调用时机的相关资料...

    windtersharp7642021-05-04
  • IOS解析iOS开发中的FirstResponder第一响应对象

    解析iOS开发中的FirstResponder第一响应对象

    这篇文章主要介绍了解析iOS开发中的FirstResponder第一响应对象,包括View的FirstResponder的释放问题,需要的朋友可以参考下...

    一片枫叶4662020-12-25
  • IOSiOS通过逆向理解Block的内存模型

    iOS通过逆向理解Block的内存模型

    自从对 iOS 的逆向初窥门径后,我也经常通过它来分析一些比较大的应用,参考一下这些应用中某些功能的实现。这个探索的过程乐趣多多,不仅能满足自...

    Swiftyper12832021-03-03
  • IOS关于iOS自适应cell行高的那些事儿

    关于iOS自适应cell行高的那些事儿

    这篇文章主要给大家介绍了关于iOS自适应cell行高的那些事儿,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的...

    daisy6092021-05-17
  • IOSIOS开发之字典转字符串的实例详解

    IOS开发之字典转字符串的实例详解

    这篇文章主要介绍了IOS开发之字典转字符串的实例详解的相关资料,希望通过本文能帮助到大家,让大家掌握这样的方法,需要的朋友可以参考下...

    苦练内功5832021-04-01
  • IOSiOS中tableview 两级cell的展开与收回的示例代码

    iOS中tableview 两级cell的展开与收回的示例代码

    本篇文章主要介绍了iOS中tableview 两级cell的展开与收回的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    J_Kang3862021-04-22