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

时间:2010-06-29 09:22:43

标签: iphone uitableview event-handling uiscrollview

我正在努力解决以下问题。我有一个带滚动视图的视图控制器。使用此滚动视图,用户应该可以滑动一组“页面” - 就像在Apple的天气应用程序中一样,所以没有什么不常见的。然后滚动视图中的每个“页面”都是表格视图,显示项目列表。在这里,我遇到了问题。

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

这种行为在我的情况下导致了一个真正的问题(滚动视图中的表视图),因为表视图是滚动视图的后代,它是在正常情况下由命中测试返回的视图,这导致所有事件都是由表视图抓取,因此它的父滚动视图从未被调用 - 因此不会执行任何滑动。

当然,当我在表视图的子类中覆盖hitTest:withEvent:方法并返回superview(实际上是滚动视图)时,情况相反 - 用户可以在页面中滑动,但不能滚动表视图。

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

我现在正在与这个问题作斗争,但是无法克服。以下是我到目前为止已经结束的内容。这里非常简单。它几乎完成了我的需要 - 除了表视图永远不会滚动...请注意我的表视图子类总是返回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如何实现事件处理,那就足够了吗?

感谢您的任何建议。

1 个答案:

答案 0 :(得分:0)

所以基本上你想在表格视图中进行垂直滚动,但是要进行水平滑动的分页?

如果您可以使用3.2+兼容性(实际上是在iPhone 4.0上),我会尝试: - 坚持使用标准组件,无需额外处理 - 使用UISwipeGestureRecognizer并将其添加到表视图中 - 如果手势识别器触发,则检查是否为水平滑动,如果是,则以编程方式更改为页面

当然,如果不需要对单元格进行滑动手势 - 即删除,则整个概念才有效。但这当然适用于所有方法。

在3.2之前,你真的需要用触摸处理器弄湿手。对UITableView进行子类化并覆盖touchesBegan:等会有我的第一次尝试(并识别水平滑动并调用分页),尽管整个解决方案都很难看。