【问题标题】:Sibling subview does not receive touches in iPhone同级子视图在 iPhone 中不接收触摸
【发布时间】:2011-12-18 21:54:37
【问题描述】:

我有一个包含两个子视图的视图 (parent),一个在另一个 (topChild) 的顶部 (bottomChild)。

如果我点击屏幕,只有topChildparent 会收到触摸事件。

我应该更改什么以将触摸事件也传播到bottomChild

代码:

- (void)viewDidLoad
{
    [super viewDidLoad];
    MYView* parent = [[MYView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
    parent.tag = 3;
    parent.backgroundColor = [UIColor redColor];

    MYView* bottomChild = [[MYView alloc] initWithFrame:CGRectMake(0, 0, 90, 90)];
    bottomChild.tag = 2;
    bottomChild.backgroundColor = [UIColor blueColor];
    [parent addSubview:bottomChild];

    MYView* topChild = [[MYView alloc] initWithFrame:CGRectMake(0, 0, 80, 80)];
    topChild.tag = 1;
    topChild.backgroundColor = [UIColor greenColor];
    [parent addSubview:topChild];
    [self.view addSubview:parent];
}

其中MYViewUIView 的子类,仅记录touchesBegan

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    NSLog(@"%d", self.tag);
    [super touchesBegan:touches withEvent:event];
}

结果:

触摸绿色区域会产生以下日志:

TouchTest[25062:f803] 1
TouchTest[25062:f803] 3

我的第一个想法是让parent 将所有touchesSomething 调用传播给它的孩子,但(A)我怀疑可能有更简单的解决方案和(B) 我不知道是哪个孩子将事件发送给了父母,向同一个视图发送两次touchesSomething 消息可能会导致恶作剧。

在提出问题后,我发现这个post 建议覆盖hitTest 以更改接收触摸的视图。如果可行,我会尝试这种方法并更新问题。

【问题讨论】:

    标签: iphone ios uiview touchesbegan uiresponder


    【解决方案1】:

    您遇到的一个有趣的问题可能最好通过重新考虑您的结构方式来解决。但是要使其按照您建议的方式工作,您需要在当前顶视图中捕获触摸事件,将其传递给父视图,然后将其向下传播到父视图的所有子视图。要完成这项工作,您需要 touchesBegan:(或任何其他用于拦截触摸的方法)在所有视图中不执行任何操作,仅在父视图调用的方法中执行操作。

    这实际上是另一种说法,不处理视图中的触摸,捕获它们但通知父视图视图,然后根据需要调用子视图方法以产生您想要的效果。

    - (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    
        // Do nothing, parent view calls my parentNotifiedTouchesBegan method
        [self.superview touchesBegan:touches withEvent:event];
    }
    
    - (void) parentNotifiedTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    
        // Act on the touch here just as my sibling views are doing
    }
    

    请注意,我在该代码中将 super 更改为 self.superview。你可能想也可能不想调用super的方法,这取决于你在做什么,调用的地方可能在parentNotifiedTouchesBegan

    你当然可以知道是哪个subView发送了事件,只需要使用自定义方法通知superview而不是调用它的touchesBegan:。使用 self 参数。

    【讨论】:

    • 感谢亚当!这个解决方案会与手势识别器兼容吗?乍一看,如果我走这条路,我将不得不重新实现轮子。
    • 我非常想重新构建事物,但我不知道如何进行。 topChild 具有透明度,topChild 和bottomChild 都可以“移动”(因此topChild 不能是bottomChild 的子视图),并且都需要响应触摸。
    • 应该有可能,您只需将回调接收到的gestureRecognizer 对象传递给父级,而不是简单的触摸。至少在我方便的项目中,这适用于 UIPinchGestureRecognizer。
    • 现在我认为您根本不需要在子视图中捕获事件,实际上您可以禁用交互以便基本视图获取所有内容。无需执行通知步骤。只需让基本视图捕获并解释所有内容并使视图起作用。您应该能够通过将点 (- (CGPoint)convertPoint:(CGPoint)point toView:(UIView *)view) 与子视图的框架 (CGRectContainsPoint) 进行比较来隔离应该获取事件的视图。
    • 这就是我现在正在尝试的!也就是说,我觉得这必须“手动”完成很奇怪。我想这是一个很常见的问题。
    【解决方案2】:

    如果你不需要孩子的触摸然后设置

    bottomChild.userInteractionEnabled = NO;
    topChild.userInteractionEnabled = NO;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-15
      • 1970-01-01
      • 1970-01-01
      • 2012-02-05
      • 2023-03-29
      相关资源
      最近更新 更多