学习及实践笔记
记录iOS中常见Modal、Push转场动画的学习及实践
相关api的记录及介绍
1 | /*这个接口用来提供切换上下文给开发者使用,包含了从哪个VC到哪个VC等各类信息*/ |
- 注意点
locationInView:获取到的是手指点击屏幕实时的坐标点;
translationInView:获取到的是手指移动后,在相对坐标中的偏移量
Modal
注意:当我们在被modal出的控制器中,向self发送dismissViewController的方法时,这个消息,会被直接转发到显示它的VC中去
Present
BouncePresentTransition的具体实现
1 | #import <Foundation/Foundation.h> |
1 | #import "SPBouncePresentTransition.h" |
在viewcontroller中如何使用
1.遵守UIViewControllerTransitioningDelegate
协议
2.设置modal的vc的transitioningDelegate
属性
3.实现代理方法
1 | -(id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source |
具体可参照如下代码
1 | #pragma mark - Transition |
效果如下
Dismiss
滑动效果的转场实现
需要注意的是,务必同时实现两个代理方法
触发顺序,为动画类->交互类
,系统会优先处理animationControllerForDismissedController
方法,如果有,则dismiss操作均为自定义dismissTransition(demo中的transitionDuration已经设置为1.5s,效果可如gif动图所示),如果没有设置,那么则为系统的dismiss动画。
1 | // 动画类 |
1 | // 交互类 |
具体可参照如下代码
1.NormalDismiss
1 | #import <Foundation/Foundation.h> |
1 | #import "SPNormalDismissTransition.h" |
2.SwipeTransition
1 | #import <UIKit/UIKit.h> |
1 | #import "SPPercentSwipeTransition.h" |
效果如下
SemiModal
实现一个常见的semi半挂式modal,将我们上述的AnimationTransition(present)、NormalDismiss部分稍作处理即可
效果如下:
首先分析实现思路:
1.semi部分,在bouncePresentTransition
中的toVC的view进行圆角处理,同时设置它在containerView中的frame为目标样式
2.背景部分,将当前fromVC的view进行截图,添加到转场容器containerView
中,然后改变它的transform
中的scale属性,进行等比例缩放,同时将底层viewController的view进行隐藏处理
3.因为上文中,我们已经处理了基于UIPercentDrivenInteractiveTransition
的swipeTransition
,所以不需要再关心百分比变化
4.上文中处理的normalDismiss
,只是简单的对视图进行了切换,因为考虑到semi的样式会对底层viewController的view进行隐藏处理,所以我们需要特别注意,在transition完成时,要将目标vc的view显示出来
思路有了,那么接下来就是实现,具体请看代码:
截图方法
1 | - (UIImage *)getSnapShotFromView:(UIView *)view{ |
改造的bouncePresent
1 | - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{ |
改造的normalDismiss
1 | - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{ |
Push&Pop
Push
在viewcontroller中如何使用
1.遵守UINavigationControllerDelegate
协议
2.设置viewcontroller.navigationController.delegate
的代理
3.实现代理方法
1 | - (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC |
这里需要特别注意一点,对于Push和Pop,都会在此方法中返回,需要我们对operation
进行类型判断,返回正确类型的自定义transition
同时要考虑一种特殊情况,就是自己并非第一层viewController时,从自身pop出去的情况
1 | if (fromVC == self && operation == UINavigationControllerOperationPop) |
(我们可以发现,Push同上文中提到的Modal的处理方式一致,只是遵守的协议不同)
先看效果
分析一下思路:
1.将点击的Cell中的imageView,传入到转场容器container中,转换其坐标、截图并添加(注意同toVC.view的添加顺序),我们命名为snapView
2.获取fromVC中的目标图片位置,设置为snapview的终点frame
大概看一下我们如何实现,写一下几个比较关键的地方
1 | // 1.fromVC,处理点击CollectionView的点击事件 |
Pop
效果如下
如果一路写到这里,想必已经明白转场动画的基本使用,所以我们不再赘述,只附效果的实现代码
1 | SPPushViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; |
** 注意!注意!注意! [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
务必在动画结束时上报转场结束状态(此处手动鲜血红) **
** 返回手势 **
只需要我们在之前写的percentSwipeTransition
中稍加改造即可,我们将它稍加封装,代码如下
1 | #import <UIKit/UIKit.h> |
1 | #import "SPPercentSwipeTransition.h" |
因为加入了手势处理,所以我们需要将Pop中上报转场完成的地方稍加改动
考虑手势取消转场的情况,取消时,将fromVC的内容再次显示即可
1 | // 开始动画 |
看一下我们的最终效果
总结
** 1.理解ContainerView的作用 **
** 2.务必上报transition结束或取消状态 **
** 3.区分UIViewControllerTransitioningDelegate
、UINavigationControllerDelegate
的使用场景 **
** 4.转场动画的关键,在于处理fromVC和toVC的view的变化,最终还是回归到UIView动画 **
** 5.体会自定义transition时,代理方法带来的简洁高效 **