如何阻止从超级视图到子视图的手势?

Posted

技术标签:

【中文标题】如何阻止从超级视图到子视图的手势?【英文标题】:How to block a gesture from superview to subview? 【发布时间】:2013-06-07 08:37:32 【问题描述】:

我正在编写一个模块,每次在视图上滑动时,都会添加两个视图大小为一半的子视图。这些子视图有自己的手势(例如:平移,...)。我第一次刷,没关系,因为没有创建任何子视图。但是一旦创建了子视图,每次我滑动时,滑动手势总是传递给它的子视图。 :(,所以我必须滑动2次才能划分。

我想知道有没有办法阻止滑动传递到它的子视图?谢谢。

更新 我使用 shouldRecognizeSimultaneouslyWithGestureRecognizer 使这些手势同时工作。但是还是有一些问题。父视图有它的滑动手势,子视图有它的平移手势。由于我使用了 souldRecognizeSimultaneouslyWithGestureRecognizer,所以有时在我平移时,会触发滑动手势。那么,您知道在这种情况下如何在 Pan 处于活动状态时禁用 Swipe 吗?

【问题讨论】:

你想要什么行为?如果子视图和父视图中都有手势识别器,显然存在冲突。 我只希望在父视图中滑动行为,而不是子视图。我没有将此手势添加到子视图中。 【参考方案1】:

你必须实现 UIGestureRecognizerDelegate 方法:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;

并将您的控制器添加为手势识别器的代表。然后,当两个手势识别器响应一个手势时,将调用此方法,您可以在此处为您的应用实现所需的逻辑。

在控制器的接口声明中你必须输入:

@interface testcViewController () <UIGestureRecognizerDelegate>

那么,在创建手势识别器时:

UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipe)];
swipe.direction = UISwipeGestureRecognizerDirectionDown;
swipe.delegate = self;
[self.view addGestureRecognizer:swipe];

然后,最后,将此方法添加到控制器:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer

    BOOL shouldInteract = NO;
    //Here you decide whether or not the two recognizers whould interact.
    return shouldInteract;

编辑 你也可以实现

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer;

在这里,检测您是否已经呈现了子视图,并阻止您想要的任何手势。

【讨论】:

【参考方案2】:

为了阻止来自超级视图的所有手势识别器,我创建了一个 UIGestureRecognizer 子类,它在附加到视图时会执行此操作。请参阅以下代码(取自我的 WEPopover 项目):

#import "WEBlockingGestureRecognizer.h"
#import <UIKit/UIGestureRecognizerSubclass.h>

@implementation WEBlockingGestureRecognizer

- (id)init 
    return [self initWithTarget:self action:@selector(__dummyAction)];


- (id)initWithTarget:(id)target action:(SEL)action 
    if ((self = [super initWithTarget:target action:action])) 
        self.cancelsTouchesInView = NO;
    
    return self;


-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    if (self.state == UIGestureRecognizerStatePossible) 
        self.state = UIGestureRecognizerStateBegan;
    


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


-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
    self.state = UIGestureRecognizerStateRecognized;


- (BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer *)preventingGestureRecognizer 
    return [self isGestureRecognizerAllowed:preventingGestureRecognizer];


- (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer 
    return ![self isGestureRecognizerAllowed:preventedGestureRecognizer];


- (BOOL)shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer 
    return ![self isGestureRecognizerAllowed:otherGestureRecognizer];


- (BOOL)shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer 
    return NO;


- (BOOL)isGestureRecognizerAllowed:(UIGestureRecognizer *)gr 
    return [gr.view isDescendantOfView:self.view];


- (void)__dummyAction 



@end

如果您想阻止附加到某个视图的父视图的所有手势识别器,只需执行以下操作:

- (void)blockParentGesturesForView:(UIView *)v 
    [v addGestureRecognizer:[WEBlockingGestureRecognizer new]];

【讨论】:

好主意,这让手势看起来像事件链,子视图会阻止超级视图手势。【参考方案3】:

将 userinteractionEnabled 设置为子视图的 NO

 subview.userinteractionEnabled=NO

如果您不想禁用 userInteraction,请使用cancelsTouchesInView 方法

cancelsTouchesInView——如果手势识别器识别出它的手势, 它会从他们的视野中解除该手势的剩余触摸(所以 窗口不会提供它们)。窗口取消之前的 使用 (touchesCancelled:withEvent:) 消息传递触摸。如果一个 手势识别器无法识别其手势,视图接收到 多点触摸序列中的所有触摸。

【讨论】:

所以它也会禁用子视图手势。我不想那样。我希望子视图可以交互。 子视图也有手势识别器,因此必须启用用户交互。【参考方案4】:

试试这样,

   - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
    return NO;

【讨论】:

【参考方案5】:

考虑到我有一个dialogView 作为我的UIViewController 的主要view 的直接子视图,我将手势识别器附加到主要view 并执行以下操作(将我的视图控制器设置为手势识别器delegate):

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool 
    let point = touch.location(in: view)
    return !dialogView.frame.contains(point)
 

【讨论】:

【参考方案6】:

采用我在这里阅读的内容并制作了一个非常棒的 Swift 5(对我来说)!我在一个视图中有一个滑动控件,该控件也有一个用于移动到另一个视图的滑动识别器。如果手指没有碰到滑块的拇指,则整个视图都会移动。

通过将此视图放置在滑块下方(已展开使其更大一些),未命中不会有任何作用。

final class BlockingView: UIView, UIGestureRecognizerDelegate 
    let swipe: UISwipeGestureRecognizer = UISwipeGestureRecognizer();

    init() 
        super.init(frame: CGRect.zero)

        swipe.direction = [.left, .right]
        self.addGestureRecognizer(swipe)
    
    required init?(coder: NSCoder)  fatalError("init(coder:) has not been implemented") 

    @objc override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool  return false 

希望这可以为某人省去麻烦!

【讨论】:

以上是关于如何阻止从超级视图到子视图的手势?的主要内容,如果未能解决你的问题,请参考以下文章

如何将手势识别器从一个视图传递到另一个视图

如何在父视图中禁用点击手势?

请问如何阻止一个手势事件向父类传递?

如何允许某些手势通过 superview 到它下面的视图?

如何将手势识别器添加到一系列子视图中?

在 SwiftUI 中,如何使手势在容器视图之外处于非活动状态?