UIScrollview 窃取触摸事件

Posted

技术标签:

【中文标题】UIScrollview 窃取触摸事件【英文标题】:UIScrollview stealing touch events 【发布时间】:2013-12-03 04:12:19 【问题描述】:

我有一个实现touchesBegan, touchesMoved, touchesEnded 的子类UIView。一切运作良好。然后,我在这个UIVIew 中添加了一个UIScrollview 作为子视图。在UIScrollview 中进行的触摸是not forwarded back up the responder chain to the parent view,因此我的 UIView 的触摸方法永远不会被调用(它们被调用用于在滚动视图之外进行的触摸就好了)。

我像这样创建了一个新的 UIScrollView 类别:

@implementation UIScrollView (forwardTouches)

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

    // If not dragging, send event to next responder
    if (!self.dragging)
        [self.nextResponder touchesBegan: touches withEvent:event];
        [self setScrollEnabled:NO];
        NSLog(@"touchesBegan");
    
    else
        NSLog(@"touchesBegan-else");
        [super touchesEnded: touches withEvent: event];
    

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event

    // If not dragging, send event to next responder
    if (!self.dragging)
        [self.nextResponder touchesMoved: touches withEvent:event];
        NSLog(@"touchesMoved");
    
    else
        NSLog(@"touchesMoved - else");
        [super touchesEnded: touches withEvent: event];
    

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event

    // If not dragging, send event to next responder
    if (!self.dragging)
        [self.nextResponder touchesEnded: touches withEvent:event];
        [self setScrollEnabled:YES];
        NSLog(@"touchesEnded");
    
    else
        NSLog(@"touchesEnded - else");
        [super touchesEnded: touches withEvent: event];
    

这实际上似乎在 iPhone 上按预期工作(即:如果用户将手指拖过滚动视图,它会滚动,但如果他将手指放在视图上并且不移动它,则父视图的 touchesBegan 方法火灾),但它不适用于 iPad。据推测,self.dragging 需要更多时间在 iPad 上,但我正在努力寻找可靠解决此问题的方法。我确定我遗漏了一些非常明显的东西。提前致谢!

使用可能的解决方案进行编辑:

经过反复试验,我想出了下面的代码。它似乎在 iPhone 和 iPad 上运行良好。为什么使用它可能是个坏主意?

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

    NSArray * myDataArray = [NSArray arrayWithObjects:touches, event, nil];

    // If not dragging, send event to next responder
    if (!self.dragging)
        [self performSelector:@selector(forwardTouches:) withObject:myDataArray afterDelay:0.5];
    
    else
        NSLog(@"touchesBegan-else");
        [super touchesEnded: touches withEvent: event];
        [NSObject cancelPreviousPerformRequestsWithTarget:self];
    


-(void)forwardTouches:(NSArray *)array
    NSSet * mySet = [array objectAtIndex:0];
    UIEvent * myEvent = [array objectAtIndex:1];

    if (!self.dragging)
        [self.nextResponder touchesBegan:mySet withEvent: myEvent];
        [self setScrollEnabled:NO];
    


-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event

    // If not dragging, send event to next responder
    if (!self.dragging)
        [self.nextResponder touchesMoved: touches withEvent:event];
        NSLog(@"touchesMoved");
    
    else
        NSLog(@"touchesMoved - else");
        [super touchesEnded: touches withEvent: event];
        [NSObject cancelPreviousPerformRequestsWithTarget:self];
    

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event

    // If not dragging, send event to next responder
    if (!self.dragging)
        [self.nextResponder touchesEnded: touches withEvent:event];
        [self setScrollEnabled:YES];
        NSLog(@"touchesEnded");
    
    else
        NSLog(@"touchesEnded - else");
        [super touchesEnded: touches withEvent: event];
        [NSObject cancelPreviousPerformRequestsWithTarget:self];
    

【问题讨论】:

您是否只是想在父视图中捕获点击事件而不中断滚动视图中的滚动? 我试图得到一个非此即彼的场景。如果用户将手指按在屏幕上并且不移动它,我希望 UIView 中的触摸方法触发,并且滚动视图不滚动。如果用户在屏幕上按下手指并移动它,我希望 UIScrollview 滚动,并且 UIView 的触摸方法不触发。 【参考方案1】:

上面的代码不是一个好的计划。 如果你想让超级视图有机会处理子视图中出现的触摸,你应该使用手势,而不是改变触摸的转发,这是危险的。

【讨论】:

由于多种原因,我无法将超级视图的代码更改为使用手势。我可以使用手势识别器来拦截滚动视图中的触摸,并将其转发给超级视图的触摸方法吗? UITapGestureRecognizer 可以满足您的需求吗?给superview添加一个UITapGestureRecognizer;当用户点击时,调用superview,当用户滚动时,调用scrollView; 是的,这可行,但我不确定如何在代码中实现。 详细说明 - 我可以轻松地将 UIGestureRecognizer 添加到视图控制器。但我不知道如何将调用传递给(自定义)视图,以及如何将其转换为它的触摸......方法? 没关系,我想通了。我必须将 UIGestureRecognizer 放入 UIView 的 awakefromnib,而不是控制器。

以上是关于UIScrollview 窃取触摸事件的主要内容,如果未能解决你的问题,请参考以下文章

UIScrollView 的触摸事件

以 UIScrollView 作为子类的 UIView 不接收触摸事件

目标 C:检测 UIScrollView 上的触摸事件

将触摸事件从 UIVew 传输到 UIScrollView

嵌入在 UIScrollview 中的 UIWebview 中的 Javascript 触摸事件

UIWebView 在 UIScrollView 内消耗触摸事件