您的位置:首页 > 移动开发 > IOS开发

关于 iOS自定义转场动画

2016-08-16 15:26 453 查看


自定义转场动画,首先得确定要做什么样的动画

1.动画类

继承自NSObject,服从协议UIViewControllerAnimatedTransitioning

既然服从这个协议,那么这个协议里的方法就要实现

这个是用来确定动画时间的,可以在第二个协议方法中用到动画时间的时候用self来调用获取

// This is used for percent driven interactive transitions, as well as for container controllers that have companion animations that might need to

// synchronize with the main animation. 

- (NSTimeInterval)transitionDuration:(nullableid
<UIViewControllerContextTransitioning>)transitionContext;

这个是用来确定做什么样的转场动画

// This method can only  be a nop if the transition is interactive and not a percentDriven interactive transition.

- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext;

2.交互类

对于动画类方面push和present转场其实都是一样的

但是对于交互类,这两者可不太相同

先说说push,pop

继承自NSObject,要服从协议UINavigationControllerDelegate

在交互类的.m文件中定义两个私有属性,一个UINavigationController属性,一个UIPercentDrivenInteractiveTransition属性,前者是该交互类对应的导航栏,后者是用来实现根据手势的完成比例更新UI的

- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationControlle *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController
*)fromVC toViewController:(UIViewController *)toVC {

    /**

     *  方法1中判断如果当前执行的是Pop操作,就返回我们自定义的Pop动画对象。

     */

    if (operation ==UINavigationControllerOperationPop)

        return [[PopAnimationalloc]init];

    returnnil;

}

- (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController
*)navigationController

                         interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController
{

    /**

     *  方法2会传给你当前的动画对象animationController,判断如果是我们自定义的Pop动画对象,那么就返回interactivePopTransition来监控动画完成度。

     */

    if ([animationControllerisKindOfClass:[PopAnimationclass]])

        returnself.interactivePopTransition;

    returnnil;

}
这两个是导航栏协议方法:第一个方法根据operation的枚举值来确定返回push动画类,还是pop动画类
第二个方法是根据animationController这个动画类的类型来返回服从了交互协议UIViewControllerInteractiveTransitioning的实例,而交互类的私有属性UIPercentDrivenInteractiveTransition正好就是一个服从该协议的类

除了协议之外,交互类还要实现pan手势触发的方法,在这个方法中做动画的更新UI的操作

/**

 *  我们把用户的每次Pan手势操作作为一次pop动画的执行

 */

- (void)handleControllerPop:(UIPanGestureRecognizer *)recognizer {

    /**

     *  interactivePopTransition就是我们说的方法2返回的对象,我们需要更新它的进度来控制Pop动画的流程,我们用手指在视图中的位置与视图宽度比例作为它的进度。

     */

    CGFloat progress = [recognizertranslationInView:recognizer.view].x
/ recognizer.view.bounds.size.width;

    /**

     *  稳定进度区间,让它在0.0(未完成)~1.0(已完成)之间

     */

    progress = MIN(1.0,MAX(0.0,
progress));

    if (recognizer.state ==UIGestureRecognizerStateBegan)
{

        /**

         *  手势开始,新建一个监控对象

         */

        self.interactivePopTransition = [[UIPercentDrivenInteractiveTransitionalloc]init];

        /**

         *  告诉控制器开始执行pop的动画

         */

        [self.vcpopViewControllerAnimated:YES];

    }

    elseif (recognizer.state
==UIGestureRecognizerStateChanged) {

        /**

         *  更新手势的完成进度

         */

        [self.interactivePopTransitionupdateInteractiveTransition:progress];

    }

    elseif (recognizer.state
==UIGestureRecognizerStateEnded || recognizer.state ==UIGestureRecognizerStateCancelled)
{

        /**

         *  手势结束时如果进度大于一半,那么就完成pop操作,否则重新来过。

         */

        if (progress >0.5) {

            [self.interactivePopTransitionfinishInteractiveTransition];

        }

        else {

            [self.interactivePopTransitioncancelInteractiveTransition];

        }

       self.interactivePopTransition =nil;

    }

}

再就是初始化方法 需要注意的是,在此处将对应的导航栏的代理设置成本交互类

- (instancetype)initWithViewController:(UIViewController *)vc

{

    self = [superinit];

    if (self) {

        self.vc = (UINavigationController
*)vc;

        self.vc.delegate =self;

    }

    returnself;

}

再说说如何使用

创建一个导航栏的子类

 UIGestureRecognizer *gesture =self.interactivePopGestureRecognizer;

    gesture.enabled =NO;

    UIView *gestureView = gesture.view;

    

    UIPanGestureRecognizer *popRecognizer = [[UIPanGestureRecognizeralloc]init];

    popRecognizer.delegate =self;

    popRecognizer.maximumNumberOfTouches =1;

    [gestureView addGestureRecognizer:popRecognizer];

  

    _navT = [[NavigationInteractiveTransitionalloc]initWithViewController:self];

    [popRecognizer addTarget:_navTaction:@selector(handleControllerPop:)];

这个是需要注意的地方

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {

    /**

     *  这里有两个条件不允许手势执行,1、当前控制器为根控制器;2、如果这个push、pop动画正在执行(私有属性)

     */

    returnself.viewControllers.count
!=1 && ![[selfvalueForKey:@"_isTransitioning"]boolValue];

}

说完了push,然后说说present,dismiss

动画类类似

说交互类

继承自NSObject,要服从协议 UIViewControllerTransitioningDelegate

(这里要说一下的是,交互类实例创建后,要把被模态出来的控制器赋值给交互类的属性)

初始化交互类

被模态出来的控制器的transitioningDelegate设置为该交互类实例

如果要支持手势滑动返回那么需要再创建一个继承自UIPercentDrivenInteractiveTransition的子类,并且以被模态出来的控制器初始化

注意手势是添加在被模态出来的控制器的view上的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: