UIView - “用户交互启用”父级为假但子级为真?

Posted

技术标签:

【中文标题】UIView - “用户交互启用”父级为假但子级为真?【英文标题】:UIView -- "user interaction enabled" false on parent but true on child? 【发布时间】:2011-05-04 17:18:35 【问题描述】:

似乎父视图上的 userInteractionEnabled=NO 将阻止所有子视图上的用户交互。它是否正确?有没有办法解决这个问题?

【问题讨论】:

是的,就是这样,这完全是愚蠢的,就像 ios 中的许多事情一样,Apple 制作简单 API 的日子在哪里?我猜那是差不多 20 年前的事了,现在 API 是由哲学家编写的。 。 . .当他们不忙于编写堆栈溢出 cmets 时。 How to get touches when parent view has userInteractionEnabled set to NO in iOS的可能重复 最佳答案在这里...***.com/questions/3427619/… 【参考方案1】:

没错,父视图上的 userInteractionEnabled 设置为 NO 将级联到所有子视图。如果您需要一些子视图来启用交互,而不是其他的,您可以将您的子视图分成两个父视图:一个 userInteractionEnabled = YES,另一个为 NO。然后将这两个父视图放在主视图中。

【讨论】:

感谢lazycs。我的想法是使用透明视图来管理一些相关的弹出菜单类型视图的布局。但是如果不可见的布局视图阻止了与它下面的东西的交互,这对我不起作用。呜呜呜…… 是的,透明视图的想法在这种情况下不起作用。可以直接将子视图添加到父视图吗? 是的,可以。在任何情况下,最好使用半透明背景。没什么大不了的。 我想知道父视图中的各种 touchesBegan: 处理程序是否可以实现为只是说“我不想要这个事件,请把它传递给我下面的人” @orion 你当然可以这样做,但它不会有用,因为 iOS 中的触摸会从子视图冒泡到父视图。如果父视图收到触摸,则表示子视图已经忽略它。【参考方案2】:

您可以继承 UIView 并覆盖 hitTest:withEvent: 以将触摸事件传递给您指定的视图 (_backView):

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event 
    UIView *view = [super hitTest:point withEvent:event];

    if (view == self) 
        view = _backView;
    

    return view;

如果触摸事件由该视图处理,它将被传递给“_backView”(可以是一个 IBOutlet,以便可以使用界面生成器进行设置);如果要由任何子视图处理,只需返回该子视图([super hitTest:point withEvent:event] 的结果;)

只要您知道需要将事件传递到哪个视图,这个解决方案就可以了;除了不知道它是否有问题,因为我们返回的视图(_backView)不是当前 UIView 的子视图!但在我的情况下效果很好。

一个更好的解决方案可能是在 Disable touches on UIView background so that buttons on lower views are clickable 那里提到使用 -pointInside:withEvent: ;与以前的解决方案相比,它更好的方式是您无需指定“_backView”来接收事件(事件只是传递给链中的下一个视图)!缺点可能是我们需要对所有子视图执行-pointInside:withEvent:(尽管开销可能可以忽略不计)

【讨论】:

感谢这里的方法和“禁用触摸..”链接。那里描述的方法看起来很干净。 hitTest 为时已晚...这是最好的答案...***.com/questions/3427619/…【参考方案3】:

我遇到了一个奇怪的情况。我有一个 UIView(称之为 V),它有一个 UIButton 作为子视图。调用这个UIButton,按钮X。下面是我用于按钮X的目标/选择器的方法。下面的self是视图V。sender参数是按钮X。

导致我出现问题的情况是,如果我触摸 UI 上的另一个按钮(在导航栏上,将此按钮称为 Y),然后很快触摸按钮 X,其中按钮 Y 操作禁用视图 V,我仍然将触摸事件发送到按钮 X。

- (void) buttonAction: (UIButton *) sender

    NSLog(@"superview: %d", sender.superview.userInteractionEnabled);  
    NSLog(@"button itself: %d", sender.userInteractionEnabled);

    // <snip>

这是输出:

2014-12-19 16:57:53.826 MyApp[6161:960615] 超级视图:0 2014-12-19 16:57:53.826 MyApp[6161:960615] 按钮本身:1

也就是说,按钮动作发生并且按钮的超级视图禁用了用户交互!并且子视图仍然启用了用户交互!

对于那些认为这似乎是人为的人,在我的应用程序的 UI 上,在 iPad 上运行(运行 iOS 8.1.2),这是我在使用应用程序时偶然出现的。这不是我最初试图生成的东西。

想法?

下面给出了我目前的解决方法,但有必要这样做似乎真的很奇怪!

- (void) buttonAction: (id) sender

    NSLog(@"superview: %d", sender.superview.userInteractionEnabled);  
    NSLog(@"button itself: %d", sender.userInteractionEnabled);
    if (! self.userInteractionEnabled) return;

    // <snip>

【讨论】:

【参考方案4】:

我为此制定了一个奇怪的解决方案,我在 tableView 单元格中有一个子视图,我希望它是可触摸的,但父级不应该...

上述解决方案都不适合我,但我找到了另一种解决方案。 转到情节提要并在父视图中添加一个 tapGestureRecognizer 以吸收对父视图的触摸。 问题解决了!

【讨论】:

【参考方案5】:

这里是解决方案 创建从“UIView”继承的类并编写覆盖“内点”的函数

class TTSView: UIView 


    
    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool 
          for view in self.subviews 
               if view.isUserInteractionEnabled, view.point(inside: self.convert(point, to: view), with: event) 
                   return true
               
           

           return false
     


那么在storyboard或xib中,superview必须使用这个类

【讨论】:

【参考方案6】:

我在 xib 中执行此操作,这是我的“自定义警报控制器”视图。

for (UIView *subview in self.superview.subviews) 

    if (![subview isEqual:self]) 
        subview.userInteractionEnabled = NO;
    

【讨论】:

以上是关于UIView - “用户交互启用”父级为假但子级为真?的主要内容,如果未能解决你的问题,请参考以下文章

如何从目标 VC 的子级为协议设置委托?

GLSurfaceView 父级为 null,即使它嵌套在 LinearLayout 中

在父级为表单的子报表中滚动

升级到 Qt 5.15 后,ListView 委托中的父级为空

CSS - 将父级的高度设置为 0,但子级 div 仍然显示

css父集设置透明 里面的内容也透明怎么解决?