userInteractionEnabled = YES时如何将触摸事件传递给superview?

Posted

技术标签:

【中文标题】userInteractionEnabled = YES时如何将触摸事件传递给superview?【英文标题】:How to pass the touch event to superview when userInteractionEnabled = YES? 【发布时间】:2014-05-06 14:23:54 【问题描述】:

我有以下设置。

+- XXXCustomControl : UIControl -------+
| A                                    |
|   +- ContentView -------------------+|
|   |                                 ||
|   |  B                              ||
|   |                                 ||
|   +---------------------------------+|
+--------------------------------------+ 

作为 UIControl 子类的 XXXCustomControl。它包含一个名为 contentView 的 UIView 类型的子视图,其大小小于控件的区域。 那个视图有.userInteractionEnabled = YES;

我需要将该属性设置为 YES,因为水平滚动视图偶尔会放在其中,并且它们需要是可滚动的。如果超级视图(在我们的例子中,内容视图不允许用户交互,这会被子视图继承。) 但与此同时,这个XXXCustomControl 需要在其内容视图中不包含滚动视图时(不仅在区域 A 中,而且在区域 B 中)是可点击的。

所以我在这里有“利益冲突”,因为我要么

1)将内容视图设置为userInteractionEnabled = NO,然后我可以在A和B的内容视图区域中点击空控件,但是我将放置在那里的滚动视图将无法滚动。..

2)将内容视图设置为userInteractionEnabled = YES,但是如果控件为空,我只能点击区域A来触发触摸事件。

我想出的一个想法是,我将属性默认设置为 NO,当我填充 contentView 时,我将其设置为 yes。当我清除 contentView 时,我将属性设置回 no。 基本上我希望它一直设置为yes,当它为空时,强制contentView将touchUpInside事件传递给它的superview。

这可能吗?

【问题讨论】:

如果你只关心点击,为什么不向子视图添加一个手势识别器,它的动作与父视图中的手势识别器相同?这似乎是最简单的实现。 你为什么不给答案?迈克尔为我工作...... 迟到总比不到好... 我认为这不是利益冲突的定义,也许是利益冲突? :) 【参考方案1】:

您可以尝试在内部视图中覆盖pointInside:withEvent: 方法。当您想将触摸转发到超级视图时,这将允许您返回 NO:

-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event

    if( /* You have content, and you want to receive touches */)
        return YES;
    else
        return NO;
    

【讨论】:

这也适用于包含在容器视图中的视图 - 允许某些控件存在于容器(超级)视图中。只需通过子视图帧进行交互 - 如果没有命中则返回 NO【参考方案2】:

您可以子类化您的子视图,并实现

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
    if (!touchedContent) 
        [[self nextResponder] touchesBegan:touches withEvent:event];
     else 
        [super touchesBegan:touches withEvent:event];
    

【讨论】:

【参考方案3】:

您可以使用另一个 UIView 来“隐藏”子视图。 *详细信息:这个 UIView 是子视图的兄弟。它与您的子视图具有相同的大小和位置,背景颜色为透明色。 *说明:新的 UIView 将进行触摸,并自动将其传递给父视图。 这种方式不需要子类化您的子视图 - 这是一个故事板解决方案。请试试这个。玩得开心!

【讨论】:

【参考方案4】:

在超级视图中使用它,无需更改子视图代码(因为子视图可​​能从其他框架或 pod 引入):

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event

    UIView *view = [super hitTest:point withEvent:event];
    if ([view isDescendantOfView:self])
    
        NSLog(@"touched inside");
    
    return view;

【讨论】:

【参考方案5】:

- 斯威夫特

override func point(inside point: CGPoint, with event: UIEvent?) -> Bool 
    if <#condition#>  return true 
    else  return false 

【讨论】:

【参考方案6】:

如果您想从超级视图(在您的情况下为 XXXCustomControl)而不是内部视图(在您的情况下为 ContentView)处理事件,您可以在您的超级视图中编写以下 swift 代码:

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? 
    guard let view = super.hitTest(point, with: event) else  return nil 
    if view.isDescendant(of: self) 
        // your custom logic
    
    return view

【讨论】:

以上是关于userInteractionEnabled = YES时如何将触摸事件传递给superview?的主要内容,如果未能解决你的问题,请参考以下文章

在 overlaySKScene 上设置 userInteractionEnabled=true/false 无效

userInteractionEnabled = YES时如何将触摸事件传递给superview?

iOS bug 日志-userInteractionEnabled

斯威夫特:userInteractionEnabled 用于纺车概念中的子视图

尽管 userInteractionEnabled = true,但 UIView 中的 UIButton 没有响应触摸事件

SKSpriteNode UserInteractionEnabled 不工作