zoukankan      html  css  js  c++  java
  • 自定义导航栏返回时的滑动手势处理

    现在使用默认模板创建的iOS App都支持手势返回功能,如果导航栏的返回按钮是自定义的那么则会失效,也可以参考这里手动设置无效。

    if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {  

      self.navigationController.interactivePopGestureRecognizer.enabled = NO;  

    }

    如果是因为自定义导航按钮而导致手势返回失效,那么可以在NavigationController的viewDidLoad函数中添加如下代码:

    - (void)viewDidLoad

    {
      [super viewDidLoad];

      __weak typeof (self) weakSelf = self;
      if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
        self.interactivePopGestureRecognizer.delegate = weakSelf;
      }
    }

    这样写了以后就可以通过手势滑动返回上一层了,但是如果在push过程中触发手势滑动返回,会导致导航栏崩溃(从日志中可以看出)。针对这个问题,我们需要在pop过程禁用手势滑动返回功能:

    - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
    {
      // fix 'nested pop animation can result in corrupted navigation bar'
      if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
        self.interactivePopGestureRecognizer.enabled = NO;
      }

      [super pushViewController:viewController animated:animated];
    }

    - (void)navigationController:(UINavigationController *)navigationController
    didShowViewController:(UIViewController *)viewController
    animated:(BOOL)animated
    {
      if ([navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
        navigationController.interactivePopGestureRecognizer.enabled = YES;
      }
    }

    除了使用系统默认的动画,还可以使用自定义过渡动画:

    - (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
    animationControllerForOperation:(UINavigationControllerOperation)operation
    fromViewController:(UIViewController *)fromVC
    toViewController:(UIViewController *)toVC
    {
      if (operation == UINavigationControllerOperationPop) {
        if (self.popAnimator == nil) {
          self.popAnimator = [WQPopAnimator new];
        }
        return self.popAnimator;
      }
      return nil;
    }

    - (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
    interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController
    {
      return self.popInteractionController;
    }

    #pragma mark -

    - (void)enablePanToPopForNavigationController:(UINavigationController *)navigationController
    {
      UIScreenEdgePanGestureRecognizer *left2rightSwipe = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(didPanToPop:)];
      //[left2rightSwipe setDelegate:self];
      [left2rightSwipe setEdges:UIRectEdgeLeft];
      [navigationController.view addGestureRecognizer:left2rightSwipe];

      self.popAnimator = [WQPopAnimator new];
      self.supportPan2Pop = YES;
    }

    - (void)didPanToPop:(UIPanGestureRecognizer *)panGesture
    {
      if (!self.supportPan2Pop) return ;

      UIView *view = self.navigationController.view;

      if (panGesture.state == UIGestureRecognizerStateBegan) {
        self.popInteractionController = [UIPercentDrivenInteractiveTransition new];
        [self.navigationController popViewControllerAnimated:YES];
      } else if (panGesture.state == UIGestureRecognizerStateChanged) {
        CGPoint translation = [panGesture translationInView:view];
        CGFloat d = fabs(translation.x / CGRectGetWidth(view.bounds));
        [self.popInteractionController updateInteractiveTransition:d];
    } else if (panGesture.state == UIGestureRecognizerStateEnded) {
      if ([panGesture velocityInView:view].x > 0) {
        [self.popInteractionController finishInteractiveTransition];
      } else {
        [self.popInteractionController cancelInteractiveTransition];
      }
      self.popInteractionController = nil;
      }
    }

    如下这个代理方法是用来提供一个非交互式的过渡动画的:

    - (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
    animationControllerForOperation:(UINavigationControllerOperation)operation
    fromViewController:(UIViewController *)fromVC
    toViewController:(UIViewController *)toVC
    {
      if (operation == UINavigationControllerOperationPop) {
        if (self.popAnimator == nil) {
          self.popAnimator = [WQPopAnimator new];
        }
        return self.popAnimator;
      }

      return nil;
    }

    而下面这个代理方法则是提供交互式动画:

    - (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
    interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController
    {
      return self.popInteractionController;
    }

    这两个组合起来使用。首先,我们需要有个动画:

    @interface WQPopAnimator : NSObject <UIViewControllerAnimatedTransitioning>

    @end

    #import "WQPopAnimator.h"

    @implementation WQPopAnimator

    - (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext
    {
      return 0.4;
    }

    - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
    {
      UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
      UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
      [[transitionContext containerView] insertSubview:toViewController.view belowSubview:fromViewController.view];

      __block CGRect toRect = toViewController.view.frame;
      CGFloat originX = toRect.origin.x;
      toRect.origin.x -= toRect.size.width / 3;
      toViewController.view.frame = toRect;

      [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
        CGRect fromRect = fromViewController.view.frame;
        fromRect.origin.x += fromRect.size.width;
        fromViewController.view.frame = fromRect;

        toRect.origin.x = originX;
        toViewController.view.frame = toRect;
      } completion:^(BOOL finished) {
        [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
      }];
    }

    @end

    其次,交互式动画是通过UIPercentDrivenInteractiveTransition 来维护的,在滑动过程中根据滑动距离来进行更新:

    } else if (panGesture.state == UIGestureRecognizerStateChanged) {
      CGPoint translation = [panGesture translationInView:view];
      CGFloat d = fabs(translation.x / CGRectGetWidth(view.bounds));
      [self.popInteractionController updateInteractiveTransition:d];

    当手势结束时要做出收尾动作:

    else if (panGesture.state == UIGestureRecognizerStateEnded) {

      if ([panGesture velocityInView:view].x > 0) {  

        [self.popInteractionController finishInteractiveTransition];  

       } else {  

         [self.popInteractionController cancelInteractiveTransition];  

      }  

      self.popInteractionController = nil;  

     }

    同样地,自定义的动画也会有上面提到的导航栏崩溃问题,也可以通过类似的方法来解决:

    - (void)navigationController:(UINavigationController *)navigationController
    didShowViewController:(UIViewController *)viewController
    animated:(BOOL)animated
    {
      if (viewController == self.navigationController.pushingViewController) {
        self.supportPan2Pop = YES;
        self.navigationController.pushingViewController = nil;
      }

    }

    补充:位于当前navgationController的第一个([0])viewController时需要设置手势代理,不响应。

  • 相关阅读:
    Hard Rock
    Codeforces Round #416 (Div. 2) B. Vladik and Complicated Book
    codeforces 793B. Igor and his way to work
    codeforces 1B Spreadsheets
    HDU 1069 Monkey and Banana
    codeforces 2B The least round way
    【机器学习】 通俗说拟合
    python-八皇后问题
    python-核心知识思维导图
    python-@property 属性
  • 原文地址:https://www.cnblogs.com/huilan/p/5515399.html
Copyright © 2011-2022 走看看