47

我有一个包含多个子视图的视图。当用户点击子视图时,子视图的大小会扩大以覆盖大部分屏幕,但其他一些子视图仍然在下方可见。

当其中一个子视图像这样“扩展”时,我希望我的应用程序忽略对其他子视图的触摸。有没有一种简单的方法可以实现这一目标?我可以编写代码来处理这个问题,但我希望有一种更简单的内置方法。

4

12 回答 12

56

希望这有助于...

[[yourSuperView subviews]
   makeObjectsPerformSelector:@selector(setUserInteractionEnabled:)
   withObject:[NSNumber numberWithBool:FALSE]];

这将禁用视图的直接子视图的 userInteraction ..然后将 userInteraction 提供给您想要的唯一视图

yourTouchableView.setUserInteraction = TRUE;

编辑:

在 iOS 中,禁用父视图上的 userInteraction 似乎不会禁用其子视图上的 userInteraction 。所以上面的代码(我的意思是带有 的代码 makeObjectsPerformSelector:只会禁用父视图的 userInteraction 。

请参阅用户 madewulf 的答案,它递归地获取所有子视图并禁用所有子视图的用户交互。或者,如果您需要在项目的许多地方禁用此视图的 userInteraction,您可以对 UIView 进行分类以添加该功能.. 这样的事情就可以了..

@interface UIView (UserInteractionFeatures)
-(void)setRecursiveUserInteraction:(BOOL)value;
@end

@implementation UIView(UserInteractionFeatures)
-(void)setRecursiveUserInteraction:(BOOL)value{
    self.userInteractionEnabled =   value;
    for (UIView *view in [self subviews]) {
        [view setRecursiveUserInteraction:value];
    }
}
@end

现在你可以打电话

[yourSuperView setRecursiveUserInteraction:NO];

此外,用户@lxt 建议在所有视图之上添加一个不可见视图是另一种方法。

于 2011-03-23T12:04:09.150 回答
47

有几种方法可以做到这一点。您可以遍历所有其他子视图和 set userInteractionEnabled = NO,但如果您有很多其他视图,这不太理想(毕竟,您必须随后重新启用它们)。

我这样做的方法是创建一个不可见的 UIView,它是整个屏幕的大小,它“阻止”所有触摸进入其他视图。有时这实际上是不可见的,有时我可能会将其设置为黑色,alpha 值为 0.3 左右。

当您扩展主子视图以填充屏幕时,您可以在其后面添加这个“阻塞”UIView(使用insertSubview: belowSubview:)。当您最小化展开的子视图时,您可以从层次结构中删除不可见的 UIView。

所以不是完全内置的,但我认为是最简单的方法。不知道这是否是您已经想到的,希望它对您有所帮助。

于 2011-03-23T12:01:41.853 回答
8

请注意 Krishnabhadra 在此处作为解决方案给出的代码:

[[yourSuperView subviews]makeObjectsPerformSelector:@selector(setUserInteractionEnabled:) withObject:[NSNumber numberWithBool:FALSE]];

这并非在所有情况下都有效,因为 [yourSuperView subviews] 仅提供超级视图的直接子视图。为了让它工作,你必须递归地迭代所有子视图:

-(void) disableRecursivelyAllSubviews:(UIView *) theView
{
    theView.userInteractionEnabled = NO;
    for(UIView* subview in [theView subviews])
    {
        [self disableRecursivelyAllSubviews:subview];
    }
}

-(void) disableAllSubviewsOf:(UIView *) theView
{
    for(UIView* subview in [theView subviews])
    {
        [self disableRecursivelyAllSubviews:subview];
    }
} 

现在调用 todisableAllSubviewsOf会做你想做的事。

如果您有很多视图,lxt 的解决方案可能会更好。

于 2012-07-18T17:25:42.977 回答
5

只是 parentView.UserInteractionEnabled = NO会做的工作。父视图将禁用所有视图子视图的用户交互。但启用它不会启用所有子视图(默认情况下 UIImageView 不可交互)。所以一个简单的方法是找到父视图并使用上面的代码,并且不需要迭代所有子视图来执行选择器。

于 2016-03-17T17:36:07.397 回答
5

我会通过放置一个superView. 然后在那个按钮的顶部,我会放置应该接受用户触摸的视图。 按钮会吞下所有的触摸,它后面的视图不会收到任何触摸事件,但按钮顶部的视图会正常接收触摸。

像这样的东西:

- (void)disableTouchesOnView:(UIView *)view {
    UIButton *ghostButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, view.frame.size.width, view.frame.size.height)];
    [ghostButton setBackgroundColor:[UIColor clearColor]];
    ghostButton.tag = 42; // Any random number. Use #define to avoid putting numbers in code.

    [view addSubview:ghostButton];
}

以及一种启用parentView.

- (void)enableTouchesOnView:(UIView *)view {
    [[view viewWithTag:42] removeFromSuperview];
}

所以,要禁用parentViev后面的所有视图yourView,我会这样做:

YourView *yourView = [[YourView alloc] initWithCustomInitializer];
// It is important to disable touches on the parent view before adding the top most view.
[self disableTouchesOnView:parentView];
[parentView addSubview:yourView];
于 2015-12-08T19:33:14.350 回答
4

将 TapGestureRecognizer 添加到您的“背景视图”(使您的正常界面“变灰”的半透明视图)并将其设置为“取消在视图中触摸”,而不添加任何操作。

let captureTaps = UITapGestureRecognizer()
captureTaps.cancelsTouchesInView = true
dimmedOverlay?.addGestureRecognizer(captureTaps)
于 2015-09-18T09:13:34.667 回答
2

我会给这个问题我的 2 美分。迭代运行 userInteractionEnabled = false 这是一种方法。另一种方法是添加一个 UIView,如下所示。

EZEventEater.h

#import <UIKit/UIKit.h>
@interface EZEventEater : UIView
@end

EZEventEater.m

#import "EZEventEater.h"
@implementation EZEventEater

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
        self.backgroundColor = [UIColor clearColor];
        self.userInteractionEnabled = false;
    }
    return self;
}


- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
   //EZDEBUG(@"eater touched");
}

- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{

}

- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{

}

在您的代码中,您添加 EZEventEater 视图以覆盖您可能阻止触摸事件的所有视图。每当您想阻止这些视图的触摸事件时,只需调用

eater.userInteractionEnabled = YES;

希望这有帮助。

于 2014-08-31T13:58:49.463 回答
0

对于我的应用程序,我认为禁用导航到应用程序的其他选项卡就足够了(在有限的时间内,我正在做一些处理):

self.tabBarController.view.userInteractionEnabled = NO;

另外,我禁用了当前的视图控制器——

self.view.userInteractionEnabled = NO;

(顺便说一下,这里提出的递归解决方案在我的应用程序中产生了奇怪的效果。禁用似乎工作正常,但重新启用有奇怪的效果——一些 UI 没有重新启用)。

于 2013-02-25T04:25:37.513 回答
0

setUserInteractionEnabled = NO在您要禁用的视图上

于 2011-03-23T12:01:44.420 回答
0

在 Swift 5 中,我通过在顶部放置一个视图(突出显示的那个)并设置:

myView.isUserInteractionEnabled = true

这不会让触摸通过它,从而忽略水龙头。

在此处输入图像描述

于 2020-09-11T05:58:20.087 回答
0

简单的解决方案。添加一个什么都不做的虚拟手势。通过将其添加到这样的扩展中使其可重用:

extension UIView {
    func addNullGesture() {
        let gesture = UITapGestureRecognizer(target: self,
                                             action: #selector(nullGesture))
        addGestureRecognizer(gesture)
    }
    
    @objc private func nullGesture() {}
}
于 2021-08-16T15:42:57.507 回答
-1

我有同样的问题,但上述解决方案没有帮助。然后我注意到呼叫 super.touchesBegan(...)是问题所在。删除此事件后,该事件仅由最顶层视图处理。

我希望这对任何人都有帮助。

于 2017-03-02T11:18:44.180 回答