只允许触摸一个 UIView
Posted
技术标签:
【中文标题】只允许触摸一个 UIView【英文标题】:Allow only one UIView to be touched 【发布时间】:2012-11-01 01:11:33 【问题描述】:我有三个UIViews
:
B1
和B2
是A
的子视图。
B1
和 B2
可能有一个或多个子视图。
我希望只能同时触摸一个视图。
例如:
用户用第一根手指触摸B1
(或其一个子视图),然后在不松开它的情况下,用第二根手指触摸B2
(或其一个子视图)。现在,B1
应该接收其范围内的所有事件,但不是B2
。反过来也是一样。
这是否有可能不继承任何这些视图?
如果没有,最简单/最干净的方法是什么?
编辑:
关于exclusiveTouch
和multipleTouchEnabled
:
这些属性对我的问题无效。
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 的 exclusiveTouch
和 multipleTouchEnabled
都设置为 YES
。
编辑:我从“B1 应该接收其范围内的所有事件”的措辞中假设您希望直接在 B1 和 B2 中接收触摸,而不是它们的子视图。如果您想将触摸限制在 B1/B2 边界但在子视图中处理它们,我认为您需要将 B1 和 B2 或 A 子类化。
编辑 2:如果 B1 和 B2 的子视图是交互式的,则需要在所有交互式子视图(递归)上将这些属性设置为 YES
。但这也使得所有子视图相互排斥,而不仅仅是在 B1 和 B2 之间。
【讨论】:
查看我对exclusiveTouch
和multipleTouchEnabled
的编辑。关于您的编辑:我希望正常处理触摸。所以说有一个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 需要指向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
我知道这不是一个非常优雅的解决方案,如果有人有更好的想法,我将不胜感激。
【讨论】:
以上是关于只允许触摸一个 UIView的主要内容,如果未能解决你的问题,请参考以下文章