只允许触摸一个 UIView

Posted

技术标签:

【中文标题】只允许触摸一个 UIView【英文标题】:Allow only one UIView to be touched 【发布时间】:2012-11-01 01:11:33 【问题描述】:

我有三个UIViews

B1B2A 的子视图。

B1B2 可能有一个或多个子视图。

我希望只能同时触摸一个视图。

例如:

用户用第一根手指触摸B1(或其一个子视图),然后在不松开它的情况下,用第二根手指触摸B2(或其一个子视图)。现在,B1 应该接收其范围内的所有事件,但不是B2。反过来也是一样。

这是否有可能不继承任何这些视图

如果没有,最简单/最干净的方法是什么?

编辑:

关于exclusiveTouchmultipleTouchEnabled

这些属性对我的问题无效。

multipleTouchEnabled: 仅确定多点触控事件是否在在同一视图中传递。因此禁用视图 A 上的多点触控(无论如何都是默认设置)不会阻止视图 B1 和 B2 同时接收触摸事件。

exclusiveTouch: 也不行。据我了解,exclusiveTouch 仅在视图框架内工作。所以在视图 B1 和 B2 上设置 exclusiveTouch 没有效果。 请参阅这两个 *** 以供参考:

Why is UIView exclusiveTouch property not blocking?

Why doesn't UIView.exclusiveTouch work?

【问题讨论】:

在视图上禁用多点触控 :) 【参考方案1】:

尝试将 B1 和 B2 的 exclusiveTouchmultipleTouchEnabled 都设置为 YES

编辑:我从“B1 应该接收其范围内的所有事件”的措辞中假设您希望直接在 B1 和 B2 中接收触摸,而不是它们的子视图。如果您想将触摸限制在 B1/B2 边界但在子视图中处理它们,我认为您需要将 B1 和 B2 或 A 子类化。

编辑 2:如果 B1 和 B2 的子视图是交互式的,则需要在所有交互式子视图(递归)上将这些属性设置为 YES。但这也使得所有子视图相互排斥,而不仅仅是在 B1 和 B2 之间。

【讨论】:

查看我对exclusiveTouchmultipleTouchEnabled 的编辑。关于您的编辑:我希望正常处理触摸。所以说有一个tableView作为视图B1的子视图,我希望能够与它正常交互。但是当我第一次接触 B2 时,我不希望用户能够与 B1 中的 tableView 进行交互。 @megamer exclusiveTouch 表示视图仅针对 窗口 进行触摸,因此如果 B1 和 B2 是您希望仅接收触摸的视图,这些设置将起作用.但是,由于您似乎希望他们的子视图接收触摸,所以它不起作用。您可以在 B1 和 B2 的每个子视图中将这些属性设置为 YES(如果它们有更多子视图,则递归),但这也会使触摸多个子视图互斥。 edit2:是的,这是一个选项,但这不是我想要的——每次我添加一个新的子视图时,我都必须考虑这一点。我想为视图 B1 和 B2 中的任何子视图找到永久/有效的解决方案。【参考方案2】:

当 B1 或 B2 被触摸时,将该视图的 exclusiveTouch 设置为 YES,然后在触摸结束时再次将其设置回 NO。这意味着只有独占视图才会收到触摸。

如果您想在独占视图的边界之外进行触摸,您可以在将其设为独占时将对该视图的引用存储在某处(myExclusiveView),然后为视图 A(或任何超级视图)覆盖 hitTest:withEvent: 并拥有它返回[myExclusiveView hitTest:withEvent:]

【讨论】:

【参考方案3】:

我相信这是没有子类化是不可能的。如果有人能证明我错了,我很乐意看到他们的解决方案。无论如何,这就是我解决它的方法:

首先,我将视图子类化为A,我将子类称为ParentView。 ParentView 需要指向B1B2 的指针。我还添加了一个额外的指针,稍后用于存储当前选定的视图。然后,我覆盖hitTest

@interface ParentView : UIView
    @property (nonatomic, strong) UIView* viewB1;
    @property (nonatomic, strong) UIView* viewB2;
    @property (nonatomic, strong) UIView* currentlyTouchedView;
@end

@implementation ParentView

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

    if (self.currentlyTouchedView == nil) 
        if (CGRectContainsPoint(self.viewB1.frame, point)) 
            self.currentlyTouchedView = viewB1;
        else if(CGRectContainsPoint(self.viewB2.frame, point)) 
            self.currentlyTouchedView = viewB2;
        
    else 
        if (!CGRectContainsPoint(self.currentlyTouchedView.frame, point)) 
            return nil;
        
    

    return [super hitTest:point withEvent:event];


@end

所以,这段代码所做的是,它存储了第一次触摸的视图。如果已经存储了一个,它会在 hitTest 上返回 nil,这会占用所有额外的触摸事件。

现在,currentlyTouchedView 在哪里设置回零?为此,我将UIWindow 子类化并覆盖sendEvent 以检查是否所有触摸都已结束:

@implementation EventOverrideWindow

- (void)sendEvent:(UIEvent *)event 
    [super sendEvent:event];
    BOOL allTouchesEnded = YES;
    for (UITouch* touch in event.allTouches) 
        if (touch.phase != UITouchPhaseCancelled && touch.phase != UITouchPhaseEnded) 
            allTouchesEnded = NO;
            break;
        
    

    if (allTouchesEnded) 
        ParentView* parentView = ((AppDelegate*)[UIApplication sharedApplication].delegate).parentView;

        parentView.currentlyTouchedView = nil;
    


@end

我知道这不是一个非常优雅的解决方案,如果有人有更好的想法,我将不胜感激。

【讨论】:

以上是关于只允许触摸一个 UIView的主要内容,如果未能解决你的问题,请参考以下文章

如何检测 UIView 上的触摸并检测单击哪个 UIView 类似于 UIButton 上的触摸?

如何让 UIView 忽略触摸而不释放它?

每个 UIView 的 ExclusiveTouch

调整大小的 UIView 上没有触摸事件

通过移动 UIView 中的区域传递触摸事件

当很清楚并且不同的uiview可以处理它们时,如何忽略最上面的uiview中的触摸事件