[英]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.