iOS - 自定义转场动画

作者: herui201211 | 来源:发表于2020-09-14 18:33 被阅读0次

    自iOS7开始,苹果支持自定义转场动画;
    完整Demo:HHTransitionAnimator

    若需自定义A控制器到B控制器的转场动画,则实现步骤如下:

    • 第一步:自定义对象HHTransitionAnimator,自定义转场动画
    @interface HHTransitionAnimator : UIPercentDrivenInteractiveTransition <UIViewControllerAnimatedTransitioning, UIViewControllerTransitioningDelegate>
    
    @end
    
    @implementation HHTransitionAnimator
    
    
     /** 转场动画时长 */
    - (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext;
    {
        return 0.3;
    }
    
     /** 转场动画具体实现 - 这里是一个渐变效果 */
    - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext;
    {
       UIView *toView = [transitionContext viewForKey:UITransitionContextToViewKey];
        [[transitionContext containerView] addSubview:toView];
        toView.alpha = 0;
        [UIView animateWithDuration:weakSelf.transitionDuration animations:^{
          toView.alpha = 1;
        }completion:^(BOOL finished) {
          [transitionContext completeTransition:YES];
        }];
    }
    
    #pragma mark - UIViewControllerTransitioningDelegate
    /** 自定义present动画 */
    - (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
    {
        return self;
    }
    @end
    
    • 第二步:使用自定义转场动画
    // A present -> B
    
    @interface ListViewController : UIViewController
    
    @property (nonatomic, strong) HHTransitionAnimator *animator; 
    
    ...
    
    - (void)onClick
    {
        UIViewController *vc = [UIViewController new];
        vc.transitioningDelegate = self.animator; //指定负责转场动画的对象
        vc.modalPresentationStyle = UIModalPresentationCustom;
        [self presentViewController:vc animated:YES completion:nil];
    }
    @end
    
    

    至此,一个简单的自定义present转场动画就做好了,当然还有自定义dismiss动画,手势驱动返回,我们一一道来:

    • 自定义dismiss动画
      1.实现animationControllerForDismissedController代理方法,返回负责dismiss动画的对象,这里返回自己
      2.又因为present和dismiss动画都会来这里:animateTransition:,所以搞个transitionType加以区分,修改后的代码如下
    @implementation HHTransitionAnimator
    
    ...
    
    - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext;
    {
        if(self.transitionType == HHViewControllerTransitionTypeDismiss){
            //dismiss动画
        }else{
          //present动画
        }
    }
    
    - (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
    {
        self.transitionType = HHViewControllerTransitionTypePresent;
        return self;
    }
    - (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
    {
        self.transitionType = HHViewControllerTransitionTypeDismiss;
        return self;
    }
    
    
    • 手势驱动返回,这里简单实现一个左滑返回效果
      1.相信细心的同学已经发现了,我们自定义的HHTransitionAnimator是继承自UIPercentDrivenInteractiveTransition的,通过继承这个类,可以方便地根据滑动距离来控制dismiss动画完成的比例
      2.给需要滑动返回的控制器view添加手势,根据手势滑动距离更新dismiss动画比例
      3.实现interactionControllerForDismissal代理方法:当处于滑动返回状态时才返回自己,否则返回nil;
      4.用interacting属性来标识是否处于滑动返回中
    - (void)addGestureToViewController:(UIViewController *)vc
    {
        UIScreenEdgePanGestureRecognizer *ges = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];
        ges.edges = UIRectEdgeLeft;
        [vc.view addGestureRecognizer:ges];
    }
    - (void)handleGesture:(UIScreenEdgePanGestureRecognizer *)ges
    {
        CGFloat progress = [ges translationInView:ges.view].x / ges.view.bounds.size.width;
        
        switch (ges.state) {
            case UIGestureRecognizerStateBegan:
            {
                self.interacting = YES;
                [self.gestureVC dismissViewControllerAnimated:YES completion:nil];
            }
                break;
            case UIGestureRecognizerStateChanged:
            {
                [self updateInteractiveTransition:progress]; //更新页面返回进度
            }
                break;
            case UIGestureRecognizerStateEnded:
            {
                self.interacting = NO;
                if (progress < 0.3) {
                    [self cancelInteractiveTransition];  //滑动距离过短,取消页面返回
                }else{
                    [self finishInteractiveTransition];  //达到滑动返回距离,继续执行页面返回动画
                }
            }
                break;
            default: break;
        }
    }
    
    #pragma mark - UIViewControllerTransitioningDelegate
    - (id<UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id<UIViewControllerAnimatedTransitioning>)animator;
    {
        return self.interacting ? self : nil;
    }
    
    @end
    

    最后,封装一下方便使用:

    
    @interface UIViewController (HHTransitionAnimator)
    
    - (void)hh_presentViewController:(UIViewController *)vc animated:(BOOL)flag TransitionAnimator:(HHTransitionAnimator *)animator completion:(void (^ __nullable)(void))completion;
    
    @end
    
    @implementation UIViewController (HHTransitionAnimator)
    
    - (void)hh_presentViewController:(UIViewController *)vc animated:(BOOL)flag TransitionAnimator:(HHTransitionAnimator *)animator completion:(void (^ __nullable)(void))completion;
    {
        self.hh_transitionAnimator = animator;
        self.hh_transitionAnimator.gestureVC = vc;
        vc.transitioningDelegate = self.hh_transitionAnimator;
        vc.modalPresentationStyle = UIModalPresentationCustom;
        dispatch_async(dispatch_get_main_queue(), ^{
            [self presentViewController:vc animated:flag completion:completion];
        });
    }
    
    
    #pragma mark - getter & setter
    - (void)setHh_transitionAnimator:(HHTransitionAnimator *)hh_transitionAnimator
    {
        objc_setAssociatedObject(self, @selector(hh_transitionAnimator), hh_transitionAnimator, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    - (HHTransitionAnimator *)hh_transitionAnimator
    {
        return objc_getAssociatedObject(self, @selector(hh_transitionAnimator));
    }
    
    @end
    
    

    使用的时候只需要调用
    - (void)hh_presentViewController:animated:TransitionAnimator:completion:方法即可

    相关文章

      网友评论

        本文标题:iOS - 自定义转场动画

        本文链接:https://www.haomeiwen.com/subject/ykpzektx.html