Iphone 只允许触摸一个UIView

Iphone 只允许触摸一个UIView,iphone,ios,ipad,events,uiview,Iphone,Ios,Ipad,Events,Uiview,我有三个ui视图: B1和B2是A的子视图 B1和B2可以有一个或多个子视图 我希望同时只能触摸一个视图。 例如: 用户用第一个手指触摸B1(或其子视图之一),然后在不松开它的情况下,用第二个手指触摸B2(或其子视图之一)。现在,B1应该接收其范围内的所有事件,而不是B2。反过来也是一样 这是否可以在不子类化这些视图的情况下实现 如果没有,最简单/最干净的方法是什么 编辑: 关于排他性触摸和多点触摸: 这些属性对我的问题无效 多点触控:仅确定是否在同一视图中传递多点触控事件。因此,禁用视图A上

我有三个
ui视图

B1
B2
A
的子视图

B1
B2
可以有一个或多个子视图

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

例如:

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

这是否可以在不子类化这些视图的情况下实现

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

编辑:

关于
排他性触摸
多点触摸

这些属性对我的问题无效

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

exclusiveTouch
:也不起作用。据我所知,
exclusiveTouch
仅在视图框架内起作用。因此,在视图B1和B2上设置
exclusiveTouch
,没有任何效果。 参考这两个StackOverflow:


尝试将B1和B2的
exclusiveTouch
multipletouched
设置为
YES

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


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

尝试将B1和B2的
exclusiveTouch
multipletouched
设置为
YES

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


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

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


如果您想在独占视图的边界之外进行触摸,您可以在使视图成为独占视图时将对该视图的引用存储在某个位置(
myExclusiveView
),然后覆盖视图a(或任何superview)的
hitTest:withEvent:
,并在触摸B1或B2时使其返回
[myExclusiveView hitTest:withEvent:
,将该视图的
exclusiveTouch
设置为
YES
,然后在触摸结束时再次将其设置为
NO
。这意味着只有独占视图才会收到触动


如果您想在独占视图的边界之外进行接触,可以在将视图设置为独占时将其引用存储在某个位置(
myExclusiveView
),然后覆盖视图a(或任何superview)的
hitTest:withEvent:
,并使其返回
[myExclusiveView hitTest:withEvent:]

我认为如果没有子类化,这是不可能的。如果有人能证明我错了,我很高兴看到他们的解决方案。不管怎样,我就是这样解决的:

首先,我将子类view
A
,我调用子类
ParentView
。ParentView需要指向
B1
B2
的指针。我还添加了一个额外的指针,稍后用于存储当前选定的视图。然后,我覆盖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

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

我相信如果没有子类化,这是不可能的。如果有人能证明我错了,我很高兴看到他们的解决方案。不管怎样,我就是这样解决的:

首先,我将子类view
A
,我调用子类
ParentView
。ParentView需要指向
B1
B2
的指针。我还添加了一个额外的指针,稍后用于存储当前选定的视图。然后,我覆盖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
我知道这不是一个非常优雅的解决方案,如果有人有更好的想法,我将不胜感激。

禁用v上的多点触控