【问题标题】:How do I prevent a UINavigationController from recognising swipes when my scroll view isn't at the far left?当我的滚动视图不在最左侧时,如何防止 UINavigationController 识别滑动?
【发布时间】:2016-11-14 20:03:33
【问题描述】:

在我的应用程序中,许多视图控制器的视图中有一个可以水平滚动的 UIScrollView,它们位于 UINavigationController 堆栈中。有时,当用户在这些视图上从左到右滚动时,他们会意外触发导航控制器的滑动手势并将当前控制器从堆栈中弹出。

这些控制器的视图都来自一个公共类。

我想要的是,如果滚动视图可以从左到右滚动,那么每次都会发生这种情况;但如果不是,则允许导航控制器的手势发生。

如何集中实现这一点?我很高兴覆盖 UINavigationController 或我的公共视图类,但我不想在每个控制器类中都向 viewWill/DidAppear/Disappear 添加东西。

【问题讨论】:

    标签: ios objective-c uiscrollview uinavigationcontroller


    【解决方案1】:

    感谢Pete Steinberger,首先我们创建了一个代理,以便我们可以拦截导航控制器的委托消息:

    #import <objc/runtime.h>
    
    @interface SGBGestureDelegateProxy : NSProxy <UIGestureRecognizerDelegate>;
    
    @property (nonatomic, weak, readonly) UINavigationController *navigationController;
    @property (nonatomic, weak, readonly) id delegate;
    
    - (id)initWithNavigationController:(UINavigationController *)navigationController delegate:(id)delegate;
    
    @end
    
    @implementation SGBGestureDelegateProxy
    
    - (id)initWithNavigationController:(UINavigationController *)navigationController delegate:(id)delegate
    {
        if (self)
        {
            _navigationController = navigationController;
    
            _delegate = delegate;
            objc_setAssociatedObject(delegate, _cmd, self, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
        }
        return self;
    }
    
    - (BOOL)respondsToSelector:(SEL)selector
    {
        return [self.delegate respondsToSelector:selector];
    }
    
    - (id)forwardingTargetForSelector:(SEL)selector
    {
        return [self.delegate respondsToSelector:selector] ? self.delegate : self;
    }
    
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
    {
        return [self.delegate methodSignatureForSelector:sel];
    }
    
    - (void)forwardInvocation:(NSInvocation *)invocation
    {
        // ignore
    }
    
    - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
    {
        UIView *topView = self.navigationController.topViewController.view;
        CGPoint topPoint = [touch locationInView:topView];
    
        for (UIView *view = [topView hitTest:topPoint withEvent:nil]; view; view = view.superview)
        {
            UIScrollView *scrollView = (UIScrollView *)view;
            if ([scrollView isKindOfClass:[UIScrollView class]] && scrollView.scrollEnabled && (scrollView.contentOffset.x != 0))
            {
                return NO;
            }
        }
    
        return [self.delegate gestureRecognizer:gestureRecognizer shouldReceiveTouch:touch];
    }
    
    @end
    

    然后我们将代理插入导航控制器的手势识别器viewDidLoad:

    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        id delegate = self.interactivePopGestureRecognizer.delegate;
        id proxy = [[C360NavigationControllerGestureDelegateProxy alloc] initWithNavigationController:self delegate:delegate];
        self.interactivePopGestureRecognizer.delegate = proxy;
    }
    

    ...我们完成了。每当用户开始滑动时,代理拦截gestureRecognizer:shouldReceiveTouch: 并在滑动开始于水平滚动的滚动视图时返回 NO。如果滚动视图没有滚动,或者没有滚动视图,则手势被识别为正常。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-28
      • 1970-01-01
      • 2013-05-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多