在我的应用程序中,许多视图控制器在其视图中都有一个可以水平滚动的UIScrollView,它们位于UINavigationController堆栈中。有时,当用户在这些视图上从左向右滚动时,他们会意外触发导航控制器的滑动手势并将当前控制器弹出堆栈。
这些控制器的视图都来自一个普通的类。
我想要的是,如果滚动视图可以从左向右滚动,那么每次都会发生这种情况;但如果没有,则允许导航控制器的手势发生。
我如何集中实现这一目标?我很乐意覆盖UINavigationController或我的常见视图类,但我不想在每个控制器类中向viewWill / DidAppear / Disappear添加内容。
答案 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。如果未滚动滚动视图,或者没有滚动视图,则手势将被识别为正常。