如何仿一个微信浮窗效果(转场动画篇)

前言

       微信的浮窗转场动画看着一闪而过,但是背后需要对转场动画的运行原理,相关类有哪些,他们都是如何作用的,又如何相互配合等了解比较透彻。
       转场动画会涉及比较广泛,相关类也不是那么容易理解清楚。但厘清后,使用转场动画会很省事并简化很多代码,而且复用和扩展也比较方便。最重要的是,转场动画的对象是控制器。这样我们可以把一些配合动画的逻辑都放在控制器中,还可以利用控制器的自带的viewdidLoad,viewwillAppeard等方法, 做更多的扩展。

微信效果展示

展示一下微信转场动画的效果,


如何仿一个微信浮窗效果(转场动画篇)_第1张图片
微信转场动画

功能分析

  1. 从侧滑方式看, 确实和系统默认相似,但从预览的效果看,不用自定义的转场动画以及侧滑,无法做到一致。所以这第一步,就是需要自定义的转场动画以及侧滑,还要做成和UINavigationController 默认的一样。

  2. 总整体分析一下, 除了UINavigationController 默认的效果外。自定义的侧滑动画过程中,有右下角按钮跟随策划进度的抽屉效果,有对手势点是否在按钮范围的监控以及手势进出按钮范围的动画。如果松手时,手势在按钮范围内,则会将控制器收藏到浮窗,而且会有一个控制器慢慢缩小并移动并生成浮窗的动画。

慢速看这个关键部分动画


如何仿一个微信浮窗效果(转场动画篇)_第2张图片
转场动画关键
  1. 我们着重分析一下,最关键部分到底做了什么。从慢速效果可以看到,表面上控制器View可是部分缩小, 但内容并没缩小,显然是用的mask,准确的说是遮挡四周留中间的mask。并且遮挡的范围一边移动一边变小,然后还有灰色背景慢慢显示,遮盖控制器显示的内容。另外浮窗上的图片也在mask留出空间慢慢显示。注意mask留出的区域是边移动边变小的,所以图片的位置也是随之移动的。
    我们总结一下:
           1) 可视部分缩小的效果, 这需要用到mask 实现。而且需要自定义maskview,再用cgpath去画图形,使中间显示,四周遮挡。再利用displayLink 不断的重绘,以实现可视部分移动并缩小的效果。
           2) 灰色背景,这个比较简单就不必多说。
           3) 图片的动画。据我测试,如果用imageview,在displaylink 中修改frame,总是无法做到和mask动画同步。那就只好用coregraphic去画图片了,顺道直接裁剪成圆角。
           这段算是分析完了。虽然只有短短的瞬间,但要做这么多事。关键是不细看,根本都感觉不到,心中顿时一万只草泥马飞过。

  2. 刚才这段动画是在触发显示浮窗之后发生的。如何处理原本的转场动画是我们接下来要分析的问题。我们可以拆分成两部分来分析。

首先,如何判断是否要取消正常的转场动画?
        从微信效果看,是在拖动手势结束时,如果手势在右下角按钮的范围内就会执行3中的动画。那我们需要在自定义的侧滑动画(一般是继承UIPercentDrivenInteractiveTransition) 来实现该效果。接下来就是通知UIViewControllerInteractiveTransitioning 对象了, 这块实现方式有很多,就不多说。

然后,最重要的第二个问题,UIViewControllerInteractiveTransitioning如何取消正常的转场动画,然后去执行3?
       这就需要说到UIViewControllerAnimatedTransitioning与UIViewControllerInteractiveTransitioning这两个类的相互关系了。UIViewControllerAnimatedTransitioning负责转场动画, 一般是用UIView.animate(withDuration:animations:completion:), 其animations Block会先执行。然后负责动画进度调度的类UIViewControllerInteractiveTransitioning ,开始不断调用update(_:)来更新动画进度。 手势结束时候,会调用finish或者cancel, 来结束或者还原动画。动画执行结束到completion block才会被调用。总之在finish, cancel调用后,只有completion block会执行,并且不是立即被调用,所以这俩都不可用。
这时就需要利用另一个在转场动画中十分重要的类UIViewControllerTransitionCoordinator。利用notifyWhenInteractionEnds(_ handler: @escaping (UIViewControllerTransitionCoordinatorContext) -> Void)方法, 绑定一个侧滑动画结束时立即执行的block, 来判断和执行3 的动画。这其中还需要注意UIViewControllerContextTransitioning.completeTransition(_:),就不能在原本的completion block 执行了,而是放在3执行完毕之后。

后记

这就是整个转场动画的实现分析了,算是整个浮窗功能的最重要的一块。
下面是我自己做的仿微信浮窗功能的源码,如果觉得还不错就给颗星吧。
仿微信浮窗源码

Tips: 用CADisplayLink做的动画,由于帧长基本相同,所以做的动画效果基本是线形变化的。如何转化非线形变换呢?最简单的方式就是将已执行的时间除以总动画时间,得到动画进度percent,然后对其做平方或者开方,这样就能得到非线形变化的percent, 当然三角函数也是不错的选择。

你可能感兴趣的:(如何仿一个微信浮窗效果(转场动画篇))