iOS实现日历翻页动画

2020-01-15 17:45:32刘景俊

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

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

做出来的效果如下图:

ios,日历翻页效果,日历开发,ios调用系统日历

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

为了得到可以沿着四个对角方向翻页的效果,我们可以先在最底部添加一个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")
}