只允许触摸一个UIView

时间:2012-11-01 01:11:33

标签: iphone ios ipad events uiview

我有三个UIViews

views

B1B2A的子视图。

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

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

例如:

用户用第一根手指触摸B1(或其中一个子视图),然后在不释放的情况下,用第二根手指触摸B2(或其中一个子视图)。现在,B1应该接收其范围内的所有事件,但不是B2。反之亦然。

这可以完成而无需继承任何这些视图吗?

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

修改

关于exclusiveTouchmultipleTouchEnabled

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

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

exclusiveTouch:也不起作用。据我所知,exclusiveTouch仅在视图框架内工作。因此,在视图B1和B2上设置exclusiveTouch无效。 请参阅以下两个stackoverflow以供参考:

Why is UIView exclusiveTouch property not blocking?

Why doesn't UIView.exclusiveTouch work?

3 个答案:

答案 0 :(得分:1)

尝试为B1和B2设置exclusiveTouchmultipleTouchEnabledYES

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

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

答案 1 :(得分:0)

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

如果您希望在独占视图范围之外进行触摸,则可以在将视图设为独占视图(myExclusiveView)时存储对该视图的引用,然后对视图A(或任何超级视图)覆盖hitTest:withEvent:并让它返回[myExclusiveView hitTest:withEvent:]

答案 2 :(得分:0)

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

首先,我将视图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

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