自定义导航栏pop动画(push同理)

本文介绍了如何自定义导航栏的pop动画,首先创建导航控制器并获取手势识别器,然后在视图上添加新的拖拽手势,同时实现UINavigationControllerDelegate代理方法和UIViewControllerAnimatedTransitioning协议来完成动画效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考推荐文章http://www.cocoachina.com/ios/20150717/12600.html
首先创建一个导航控制器 并获取控制器的手势识别器->获取视图->在视图上添加新建的拖拽手势->最后实现监听
 //获取手势识别器
 UIGestureRecognizer *gesture = self.interactivePopGestureRecognizer;
 //禁用
    gesture.enabled = NO;
    UIView *gestureView = gesture.view;
    //添加手势
    UIPanGestureRecognizer *popRecognizer = [[UIPanGestureRecognizer alloc] init];
    popRecognizer.delegate = self;
    popRecognizer.maximumNumberOfTouches = 1;
    [gestureView addGestureRecognizer:popRecognizer];
    //添加监听并在类内部实现监听方法
    [popRecognizer addTarget:[[NavigationInteractiveTransition alloc] init] action:@selector(StartDragPop:)];

实现监听方法

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

    //    translationInView获取手指在当前视图的位置
    CGFloat progress = [recognizer translationInView:recognizer.view].x / recognizer.view.bounds.size.width;

    if (recognizer.state == UIGestureRecognizerStateBegan) {

         // 告诉控制器开始执行pop的动画
        [self.vc popViewControllerAnimated:YES];
    }
    else if (recognizer.state == UIGestureRecognizerStateChanged) {

//更新手势的完成进度
        [self.interactivePopTransition updateInteractiveTransition:progress];
    }
    else if (recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateCancelled) {

   //手势结束时如果进度大于一半,那么就完成pop操作否则变回原样。
        if (progress > 0.5) {
            [self.interactivePopTransition finishInteractiveTransition];

        }else {
                [self.interactivePopTransition cancelInteractiveTransition];

        }
         self.interactivePopTransition = nil;

    }

}
要求监听者实现UINavigationControllerDelegate代理方法
//如果这里返回nil 则不会调用方法2
//方法返回自定义动画
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
                                  animationControllerForOperation:(UINavigationControllerOperation)operation
                                               fromViewController:(UIViewController *)fromVC
                                                 toViewController:(UIViewController *)toVC {
    //判断如果是pop操作
    if (operation == UINavigationControllerOperationPop)
    // 自定义Pop动画对象
        return [[PopAnimation alloc] init];

    return nil;
}
//返回动画进度
- (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
                         interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController {
//如果是我们自定义的Pop动画对象,那么就返回interactivePopTransition来监控动画完成度。
    if ([animationController isKindOfClass:[PopAnimation class]])
    //这里需要提前创建interactivePopTransition
        return self.interactivePopTransition;

    return nil;
}
PopAnimation类要求实现UIViewControllerAnimatedTransitioning协议
- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext {
    //这个方法返回动画执行的时间
    return 0.25;
}

//在这个方法中进行自定义动画
// transitionContext,用来获取一系列动画执行相关的对象。
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
    //  获取动画来自的那个控制器
    UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    //  获取转场到的那个控制器
    UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

    //获取容器视图
    UIView *containerView = [transitionContext containerView];
    self.containerView = containerView;
    //将视图添加到容器视图
    [containerView insertSubview:toViewController.view belowSubview:fromViewController.view];
    NSTimeInterval duration = [self transitionDuration:transitionContext];
    // 执行动画
    [UIView animateWithDuration:duration animations:^{
        fromViewController.view.transform = CGAffineTransformMakeTranslation([UIScreen mainScreen].bounds.size.width, 0);

    }completion:^(BOOL finished) {
        //无论转场是否被取消,动画是否执行完成都必须调用 .否则,系统不做其他事件处理,界面卡死.
        [transitionContext completeTransition:!transitionContext.transitionWasCancelled];
    }];

}

补充:

// 通过这个方法 能够获得前后两个 ViewController 的frame,用来布局视图对象空间位置
- (CGRect)initialFrameForViewController:(UIViewController *)vc;
- (CGRect)finalFrameForViewController:(UIViewController *)vc;
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值