【发布时间】:2010-06-29 09:22:43
【问题描述】:
我正在努力解决以下问题。我有一个带有滚动视图的视图控制器。使用这个滚动视图,用户应该能够滑动浏览一组“页面”——就像在苹果的天气应用程序中一样,所以没什么不寻常的。然后滚动视图中的每个“页面”都是表格视图,显示项目列表。在这里,我正在解决问题。
问题是滚动视图拦截所有触摸以查看用户是否移动了他的手指或只是点击了某个子视图内的某个点,并且它不会将事件传递给它的子视图(或超级视图)以防它识别到移动。
在我的情况下,这种行为导致了一个真正的问题(滚动视图中的表视图),因为表视图是滚动视图的后代,并且它是在正常情况下通过命中测试返回的视图,这会导致所有事件都是被表格视图抓取,所以它的父滚动视图永远不会被调用 - 所以不会执行滑动。
当然,当我在我的表格视图子类中重写 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 是如何处理事件的?
感谢您的任何建议。
【问题讨论】:
标签: iphone uitableview event-handling uiscrollview