繁体   English   中英

如何在响应者链中正确转发UITouch事件?

[英]How to properly forward UITouch events in responder chain?

我正在努力解决以下问题。 我有一个带有滚动视图的视图控制器。 使用此滚动视图,用户应该能够在“页面”集之间滑动-就像在苹果的气象应用程序中一样,因此没有什么不常见的。 然后,滚动视图中的每个“页面”都是表格视图,显示项目列表。 在这里,我要解决问题。

问题在于,滚动视图会拦截所有触摸,以查看用户是否移动了手指或只是在某个子视图中轻击了某个点,并且它不会将事件传递到其子视图(或超级视图)以防万一它识别出移动。

在我的情况下,此行为引起了一个真正的问题(滚动视图中的表视图),因为表视图是滚动视图的后代,并且该视图在正常情况下是通过点击测试返回的,这导致所有事件都被表捕获视图,因此永远不会调用其父滚动视图-因此永远不会执行滑动。

自然地,当我在表视图的子类中重写hitTest:withEvent:方法并返回一个超级视图(实际上是滚动视图)时,情况就相反了-用户可以在页面中滑动,但不能滚动表视图。

因此,我需要弄清楚的是如何-在任何级别上-确定用户想要执行的操作(滑动或向下/向上滚动表视图),然后将事件流传递给适当的组件。

我现在正与这个问题作斗争,但是无法克服。 到目前为止,我已经总结了以下内容。 这里非常简化。 它几乎满足了我的需要-除了从不滚动表视图外……请注意,我的表视图子类始终返回self.superview,即滚动视图。

/// UIViewController

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

    [super touchesBegan: touches withEvent: event];

    /// Save initial touch location for later use
    _motionStart = [[touches anyObject] locationInView: self.scrollView];

    /// Save reference to initial event
    _initialEvent = event;

    /// Fire timer
    _gestureTimer = [NSTimer scheduledTimerWithTimeInterval: 0.2
                                 target:self selector:@selector(gestureTimer:)
                               userInfo: touches repeats: NO];
}

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

    if(!_gestureTimer && !_forwardingTouchesToTableView) {
    /// If no timer is running and no event forwarding is performed, pass to super
        [super touchesMoved: touches withEvent: event];
    }
    else {
        /// Pass event to currently visible tableview
        [self.scrollView.centerPage touchesMoved: touches withEvent: event];
    }

}

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

    [super touchesEnded: touches withEvent: event];

    if(_forwardingTouchesToTableView) {
        [self.scrollView.centerPage touchesEnded: touches withEvent: event];
    }

    /// Reset state
    _motionStart = CGPointZero;

    _forwardingTouchesToTableView = NO;
}

- (void) gestureTimer: (NSTimer *) timer {

    _gestureTimer = nil;

    NSSet *touches = (NSSet *)timer.userInfo;   
    UITouch *touch = (UITouch *)[touches anyObject];

    CGPoint currentTouchLocation = [touch locationInView: self.scrollView];

    float deltaX = fabs(_motionStart.x - currentTouchLocation.x);
    float deltaY = fabs(_motionStart.y - currentTouchLocation.y);

    if(deltaY >= 4.0 && deltaX <= 12.0) {

        /// Vertical move, forward to tableview
        [self.scrollView cancelTouches];
        _forwardingTouchesToTableView = YES;
        [self.scrollView.centerPage touchesBegan: touches  withEvent: _initialEvent];
        _initialEvent = nil;
    }
    else {
        /// Horizontal swipe - just reset state
        _initialEvent = nil;
        _forwardingTouchesToTableView = NO;
    }
}

老实说,我还没有下一步要做什么。 我为找到的这个问题尝试了很多解决方案,但是它们都没有真正起作用。 我将不胜感激任何建议或提示。 如果有人可以解释如何通过UIScrollView或UITableView实现事件处理,就足够了吗?

感谢您的任何建议。

因此,基本上,您希望在表格视图中进行垂直滚动,但要进行水平滑动页面调度?

如果您可以实现3.2+兼容性(实际上是在iPhone 4.0上),那么我将尝试:-坚持使用标准组件并且没有多余的花哨处理-使用UISwipeGestureRecognizer并将其添加到表格视图中-如果手势识别器可触发,则检查如果是水平滑动,则是否以编程方式切换到页面

当然,只有在不需要对单元格进行滑动手势(即删除)的情况下,整个概念才起作用。 但这当然对所有方法都有效。

在3.2之前,您确实需要用触摸处理器弄湿手。 继承UITableView的子类并覆盖touchesBegan:等。虽然整个解决方案都很丑陋,但我将首先尝试(识别水平滑动并调用分页)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM