iOS 定制controller过渡动画 ViewController Custom Transition使用体会

最近学习了一下ios7比较重要的一项功能,就是 controller 的 custom transition。

在ios7中,navigation controller 中就使用了交互式过渡来返回上级界面,可以通过设置interactivePopGestureRecognizer.enabled 来关闭这个效果。

请参阅 ,写的非常好,建议2篇文章都要读读

http://onevcat.com/2013/10/vc-transition-in-ios7/

http://www.teehanlax.com/blog/custom-uiviewcontroller-transitions/

我测试用的是modelview 的present 和dismiss,没有试验navigationController的push,pop,和tabbarController的选择.


先说说在实现non-interactive动画时,遇到的问题。

在写demo时,用了controller.modalPresentationStyle = UIModalPresentationCustom;  就无法在- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext函数中通过toViewController.frame 获得 frame了,全是0,开始想不通,后来发现,之所以不用UIModalPresentationCustom时,可以获得frame,是因为系统通过modalPresentationStylez为toViewController.frame设定了初始值,而用了UIModalPresentationCustom,系统就不管toViewController.frame的初始化了,自然要自己指定frame了!这也才是custom的意义,自定义弹出开始和结束时的frame。另外还有一个问题,如果使用了controller.modalPresentationStyle = UIModalPresentationCustom,并且屏幕经过了旋转90度,transitionContext的containerView的坐标系并不会一起旋转,结果就是,先旋转,再present出controller,那么controller的frame就错了。 

但是如果不使用UIModalPresentationCustom,而使用其他的style(在ipad上测试),同时使用自定义动画,要么会产生视图bug(UIModalPresentationFormSheet和UIModalPresentationPageSheet),要么还是像以前一样,会把原来controller的view从hierarchy上移掉(UIModalPresentationFullScreen,UIModalPresentationNone)!就达不到同时现实2个controller的view的效果了。如果仅仅想更改动画效果,不需要2个controller同时出现,那么不应该使用UIModalPresentationCustom。如果使用了UIModalPresentationCustom,那么就需要针对屏幕的各个方向,调整自定义动画的start frame 和 end frame。比如需要支持4个方向,那么就需要4组start frame 和 end frame,这样才能达到不同方向,相同的弹出效果。


再说说实现interactive动画时,遇到的问题。

由于要支持交互,view的中间坐标变换实现比较复杂,为了简化编码工作,苹果提供了一个类:UIPercentDrivenInteractiveTransition,这个类实现了UIViewControllerInteractiveTransitioning

接口的startInteractiveTransition方法,并且提供了3个简便的控制函数,

- (void)updateInteractiveTransition:(CGFloat)percentComplete;  //根据percentComplete自动更新动画,可以自己重写

- (void)cancelInteractiveTransition; //取消过渡,返回过渡之前的状态,可以自己重写

- (void)finishInteractiveTransition; //完成过渡,达到过渡后的状态,可以自己重写

这样,实现一个交互的transition便简单了,你只需要在interactionControllerForPresentation这个代理方法中提供一个UIPercentDrivenInteractiveTransition对象A,系统会把这个对象A和UIViewControllerTransitioningDelegate对象相关联,当A对象在手势处理等方法中被发送updateInteractiveTransition等消息时,A对象会通过UIViewControllerTransitioningDelegate对象中实现的non-interactive动画 和 自己的percentComplete来自动计算具体的view的显示效果并予以显示(This style of interaction controller should only be used with an animator that implements a CA style transition in the animator's animateTransition: method.),当然,你也可以不实现non-interactive动画,而重写startInteractiveTransition等4个函数,也能实现想要的效果,但是对于复杂的变化,view的计算会很复杂!所以,建议实现animateTransition:方法。

观察UIViewControllerInteractiveTransitioning协议,只有一个必须实现的代理函数startInteractiveTransition,其实这个函数的主要目的,就是在交互开始时,能够把对应的transitionContext传递给编程人员,对transitionContext进行设置,比如添加view[containerView addSubview:[toCollectionViewController view]]; 或者保存transitionContext的引用,以便在其他函数中,通过调用transitionContext的updateInteractiveTransition,finishInteractiveTransition,cancelInteractiveTransition 进行交互操作。(id <UIViewControllerContextTransitioning>)transitionContext才是交互式过渡的主角。

另外,如果在返回UIViewControllerInteractiveTransitioning的代理中返回了对象,那么系统会认为你要使用交互式的过渡,在相应的过渡发生时,自动调用startInteractiveTransition,如果不想startInteractiveTransition被调用,要在代理方法中返回nil。


 再简要的总结一下,主要分3步。

第一,要有一个UIViewControllerTransitioningDelegate,这个代理会为相应的controller提供4个用于过渡的对象,

- (id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController: //提供non-interaction的present动画对象 

- (id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed;//提供non-interaction的dismiss动画对象 

- (id <UIViewControllerInteractiveTransitioning>)interactionControllerForPresentation:(id <UIViewControllerAnimatedTransitioning>)animator; //提供interaction的present的动画对象 

- (id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id <UIViewControllerAnimatedTransitioning>)animator;//提供interaction的dismiss动画对象

第二,需要创建这4个对象,对于non-interaction的情况(前2个代理函数),要创建一个实现实现UIViewControllerAnimatedTransitioning的类,并实现animateTransition方法。对于interaction的情况(后两个代理函数),最好不创建实现UIViewControllerInteractiveTransitioning的类,直接使用UIPercentDrivenInteractiveTransition类。

第三,如果要使用interaction的transition,还需要多做一步,就是在view上加载gesture,并在gesture的代理函数中不断调用 UIPercentDrivenInteractiveTransition 的 updateInteractiveTransition来更新动画。


另外,当使用在UINavigationController中使用2个UICollectionViewController进行导航时,可以通过设置UICollectionViewController对象的useLayoutToLayoutNavigationTransitions属性,设置正确后,navigation controller在这2个controller之间导航时就不会使用默认的左右滑动,而会把layout的变化应用为动画,来体现push和pop。具体效果和实现,请参与苹果demo :Collection View Transition,效果很炫。如果需要把这种transition做成interactive的,那么需要更多复杂工作,因为这里涉及了navigation,和 collection中的各个subview的过渡,与collectionView 过渡相关的函数也很杂乱,请参考demo中的代码。

   

原文地址:https://www.cnblogs.com/breezemist/p/3460497.html