UIView——“启用用户交互”对父母错误但对孩子正确?

发布于 2024-11-04 18:43:58 字数 76 浏览 0 评论 0原文

看来父视图上的 userInteractionEnabled=NO 将阻止所有子视图上的用户交互。这是正确的吗?有什么办法解决这个问题吗?

It appears that userInteractionEnabled=NO on a parent view will prevent user interaction on all subviews. Is this correct? Is there any way around this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

香草可樂 2024-11-11 18:43:58

这是正确的,在父视图上将 userInteractionEnabled 设置为 NO 将向下级联到所有子视图。如果您需要某些子视图启用交互,但不需要其他子视图,则可以将子视图分成两个父视图:一个使用 userInteractionEnabled = YES,另一个使用 NO。然后将这两个父视图放入主视图中。

That's correct, userInteractionEnabled set to NO on a parent view will cascade down to all subviews. If you need some subviews to have interaction enabled, but not others, you can separate your subviews into two parent views: one with userInteractionEnabled = YES and the other NO. Then put those two parent views in the main view.

平定天下 2024-11-11 18:43:58

您可以子类化 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 的子视图!但在我的例子中效果很好。

更好的解决方案可能是中提到的
禁用 UIView 背景上的触摸,以便下部视图上的按钮是可点击的 其中提到使用 -pointInside:withEvent: ;与以前的解决方案相比,它更好的是您不需要指定“_backView”来接收事件(事件只是传递到链中的下一个视图)!缺点可能是我们需要在所有子视图上执行 -pointInside:withEvent: (不过开销可能可以忽略不计)

You can subclass UIView and override hitTest:withEvent: in a way to pass touch events to a view that you specify (_backView):

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

    if (view == self) {
        view = _backView;
    }

    return view;
}

If the touch event was to be handled by this view it would be passed to "_backView" (that can be an IBOutlet so that it can be set using interface builder) ; and if it was to be handled by any child view just return that child (the result of [super hitTest:point withEvent:event];)

This solution is fine as long as you know what view you need to pass the events to; besides don't know if it has problems since we are returning a view (_backView) that is not a subview of the current UIView !! but it worked fine in my case.

A better solution might be the one mentioned in
Disable touches on UIView background so that buttons on lower views are clickable There its mentioned to use -pointInside:withEvent: ; compared to previous solution its better in the way that you don't need to specify a '_backView' to receive the events (the event is simply passed to the next view in chain)! drawback might be that we need to perform -pointInside:withEvent: on all subviews (might be of negligible overhead though)

柠檬色的秋千 2024-11-11 18:43:58

这是解决方案
创建从“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
     }

}

,然后在故事板或xib中,超级视图必须使用此类

Here is solution
Create class that inherited from "UIView" and write func that override "inside point"

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
     }

}

then in storyboard or xib, the superview have to use this class

忘你却要生生世世 2024-11-11 18:43:58

我刚刚遇到了一个奇怪的情况。我有一个 UIView(称之为 V),它有一个 UIButton 作为子视图。将此 UIButton 称为按钮 X。下面是我用于按钮 X 的目标/选择器的方法。下面的 self 是视图 V。发送者参数是按钮 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>
}

I just ran into an odd situation. I have a UIView (call this, V), which has a UIButton as a subview. Call this UIButton, button X. Below is the method I'm using for the target/selector of button X. self below is the view V. The sender parameter is button X.

The situation that's causing me an issue is that if I touch another button on my UI (on the nav bar, call this button Y) and then very quickly touch button X, where the the button Y action disables view V, I still get the touch event sent to button X.

- (void) buttonAction: (UIButton *) sender
{
    NSLog(@"superview: %d", sender.superview.userInteractionEnabled);  
    NSLog(@"button itself: %d", sender.userInteractionEnabled);

    // <snip>
}

Here's the output:

2014-12-19 16:57:53.826 MyApp[6161:960615] superview: 0
2014-12-19 16:57:53.826 MyApp[6161:960615] button itself: 1

That is, the button action occurred and the button's superview had user interaction disabled! And the subview still had user interaction enabled!!

For those of you thinking that this seems artificial, on my app's UI, running on an iPad (running iOS 8.1.2), this came up by accident in my use of the app. It was not something I was originally trying to generate.

Thoughts?

My current workaround is given below, but it seems really odd that it's necessary!

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

    // <snip>
}
少钕鈤記 2024-11-11 18:43:58

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

上述解决方案都不适合我,但我找到了另一个解决方案。
转到故事板并向父视图添加一个 tapGestureRecognizer 以吸收父视图上的触摸。
问题解决了!

I made up a weird solution for this, I had a child view in a tableView cell that I wanted to be touchable but the parent shouldn't have...

Neither of above solutions worked for me, but I found another solution.
Go to storyboard and add a tapGestureRecognizer to the parent view to absorb touches on parent view.
Problem solved!

情绪失控 2024-11-11 18:43:58

您可以在透明视图中使用 hitTest 函数,执行所有手势并点击“穿过”视图

class PassthroughView: UIView {
    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        let view = super.hitTest(point, with: event)
        return view == self ? nil : view
    }
}

You can use hitTest function in transparent view, to carry out all gestures and taps "through" the view

class PassthroughView: UIView {
    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        let view = super.hitTest(point, with: event)
        return view == self ? nil : view
    }
}
破晓 2024-11-11 18:43:58

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

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

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

I´m doing this in a xib which is my "custom alert controller"-view.

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

    if (![subview isEqual:self]) {
        subview.userInteractionEnabled = NO;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文