当滚动视图不在最左侧时,如何防止UINavigationController识别滑动?

时间:2016-07-12 14:08:23

标签: ios objective-c uiscrollview uinavigationcontroller

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

这些控制器的视图都来自一个普通的类。

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

我如何集中实现这一目标?我很乐意覆盖UINavigationController或我的常见视图类,但我不想在每个控制器类中向viewWill / DidAppear / Disappear添加内容。

1 个答案:

答案 0 :(得分:0)

感谢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。如果未滚动滚动视图,或者没有滚动视图,则手势将被识别为正常。