如何禁用除最顶层视图之外的所有视图的触摸输入?
我有一个包含多个子视图的视图。当用户点击子视图时,子视图的大小会扩展以覆盖大部分屏幕,但其他一些子视图在下面仍然可见。
当子视图之一像这样“展开”时,我希望我的应用程序忽略对其他子视图的触摸。有没有一种简单的方法可以实现这一目标?我可以编写代码来处理这个问题,但我希望有一种更简单的内置方法。
I have a view with multiple subviews. When a user taps a subview, the subview expands in size to cover most of the screen, but some of the other subviews are still visible underneath.
I want my app to ignore touches on the other subviews when one of the subviews is "expanded" like this. Is there a simple way to achieve this? I can write code to handle this, but I was hoping there's a simpler built-in way.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
希望这个帮助...
这将禁用视图的直接子视图的 userInteraction ..然后将 userInteraction 提供给您想要的唯一视图
编辑:
似乎在 iOS 中禁用父视图上的 userInteraction 不会禁用其子视图上的 userInteraction .. 所以上面的代码(我的意思是带有
makeObjectsPerformSelector:
的代码)只能用于禁用父级直接子视图的 userInteraction..请参阅用户 madewulf 的回答递归获取所有子视图并禁用所有子视图的用户交互。或者,如果您需要在项目中的许多地方禁用此视图的 userInteraction,您可以对 UIView 进行分类以添加该功能.. 这样的事情就可以了..
现在您可以调用
另外用户@lxt的建议,在顶部添加不可见视图所有视图的另一种方式是这样做的..
Hope this help...
which will disable userInteraction of a view's immediate subviews..Then give userInteraction to the only view you wanted
EDIT:
It seems in iOS disabling userInteraction on a parent view doesn't disable userInteraction on its childs.. So the code above (I mean the one with
makeObjectsPerformSelector:
)will only work to disable userInteraction of a parent's immediate subviews..See user madewulf's answer which recursively get all subviews and disable user interaction of all of them. Or if you need to disable userInteraction of this view in many places in the project, You can categorize UIView to add that feature.. Something like this will do..
Now you can call
Also user @lxt's suggestion of adding an invisible view on top of all view's is one other way of doing it..
有几种方法可以做到这一点。您可以遍历所有其他子视图并设置
userInteractionEnabled = NO
,但如果您有许多其他视图,则这不太理想(毕竟,您必须随后重新启用它们)。我这样做的方法是创建一个不可见的 UIView,它的大小与整个屏幕相同,“阻止”所有触摸进入其他视图。有时这实际上是不可见的,有时我可能会将其设置为黑色,alpha 值为 0.3 左右。
当您展开主子视图以填充屏幕时,您可以在其后面添加此“阻塞”UIView(使用
insertSubview: BelowSubview:
)。当您最小化展开的子视图时,您可以从层次结构中删除不可见的 UIView。所以不太内置,但我认为最简单的方法。不知道您是否已经想到了这一点,希望对您有所帮助。
There are a couple of ways of doing this. You could iterate through all your other subviews and set
userInteractionEnabled = NO
, but this is less than ideal if you have lots of other views (you would, after all, have to subsequently renable them all).The way I do this is to create an invisible UIView that's the size of the entire screen that 'blocks' all the touches from going to the other views. Sometimes this is literally invisible, other times I may set it to black with an alpha value of 0.3 or so.
When you expand your main subview to fill the screen you can add this 'blocking' UIView behind it (using
insertSubview: belowSubview:
). When you minimize your expanded subview you can remove the invisible UIView from your hierarchy.So not quite built-in, but I think the simplest approach. Not sure if that was what you were thinking of already, hopefully it was of some help.
请注意 Krishnabhadra 此处作为解决方案给出的代码:
这并非在所有情况下都有效,因为 [yourSuperView subviews] 只提供超级视图的直接子视图。为了使其工作,您必须在所有子视图上递归迭代:
现在调用
disableAllSubviewsOf
将执行您想要执行的操作。如果您有很深的视图堆栈,lxt 的解决方案可能会更好。
Beware of the code given as solution here by Krishnabhadra:
This will not work in all cases because [yourSuperView subviews] only gives the direct subviews of the superview. To make it work, you will have to iterate recursively on all subviews:
Now a call to
disableAllSubviewsOf
will do what you wanted to do.If you have a deep stack of views, the solution by lxt is probably better.
我会通过放置一个与
superView
具有相同框架的自定义透明按钮来实现此目的。然后在该按钮的顶部我将放置应该接受用户触摸的视图。按钮将吞掉所有触摸,其后面的视图不会接收任何触摸事件,但按钮顶部的视图将正常接收触摸。
像这样的东西:
以及启用
parentView
的方法。因此,要禁用
yourView
后面的parentViev
中的所有视图,我会这样做:I would do this by putting a custom transparent button with the same frame as the
superView
. And then on top of that button I would put view that should accept user touches.Button will swallow all touches and views behind it wouldn't receive any touch events, but view on top of the button will receive touches normally.
Something like this:
And a method for enabling the
parentView
.So, to disable all views in the
parentViev
behindyourView
, I would do this:只需
parentView.UserInteractionEnabled = NO
即可完成工作。父视图将禁用所有视图子视图上的用户交互。但是启用它不会启用所有子视图(默认情况下UIImageView不可交互)。所以一个简单的方法就是找到父视图并使用上面的代码,并且不需要迭代所有子视图来执行选择器。
Just
parentView.UserInteractionEnabled = NO
will do the work.Parent view will disable user interaction on all the view's subviews. But enable it does not enable all subviews(by default UIImageView is not interactable). So an easy way is find the parent view and use the code above, and there is no need to iterate all subviews to perform a selector.
将 TapGestureRecognizer 添加到您的“背景视图”(使您的正常界面“变灰”的半透明视图)并将其设置为“取消视图中的触摸”,而不添加操作。
Add a TapGestureRecognizer to your "background view" (the translucent one which "grays out" your normal interface) and set it to "Cancels Touches In View", without adding an action.
我将为这个问题付出 2 美分。
迭代运行 userInteractionEnabled = false 这是一种方法。
另一种方法是添加一个 UIView,如下所示。
EZEventEater.h
EZEventEater.m
在您的代码中,您添加 EZEventEater 视图以覆盖可能阻止触摸事件的所有视图。
每当您想要阻止这些视图的触摸事件时,只需调用
希望这有帮助即可。
I will give my 2 cents to this problem.
Iteratively run userInteractionEnabled = false it's one way.
Another way will be add a UIView like following.
EZEventEater.h
EZEventEater.m
In your code you add the EZEventEater view to cover all the views that your may block the touch event.
Whenever you want to block the touch event to those views, simply call
Hope this helpful.
在 Swift 5 中,我通过在顶部放置一个视图(突出显示的视图)并设置:
这不会让触摸穿过它,从而忽略点击,从而实现了此行为。
In Swift 5, I achieved this behaviour by placing a view right on top(the highlighted one) and setting:
This does not let the touches go through it, thus ignoring the taps.
对于我的应用程序,我认为禁用导航到应用程序的其他选项卡就足够了(在有限的时间内,当我正在进行一些处理时):
另外,我禁用了当前的视图控制器 -
(并且,顺便说一句,此处提出的递归解决方案在我的应用程序中产生了奇怪的效果,禁用似乎工作正常,但重新启用却产生了奇怪的效果——某些 UI 未重新启用。
For my app, I think it will be sufficient to disable navigation to other tabs of the app (for a limited duration, while I'm doing some processing):
Also, I disabled the current view controller--
(And, by the way, the recursive solutions proposed here had odd effects in my app. The disable seems to work fine, but the re-enable has odd effects-- some of the UI was not renabled).
简单的解决方案。添加一个不执行任何操作的虚拟手势。通过将其添加到扩展中,使其可重用,如下所示:
Simple solution. Add a dummy gesture that does nothing. Make it reusable by adding it to an extension like this:
在要禁用的视图上
setUserInteractionEnabled = NO
setUserInteractionEnabled = NO
on the view you want to disable我遇到了同样的问题,但上述解决方案没有帮助。
然后我注意到打电话
super.touchesBegan(...)
就是问题所在。删除此事件后,该事件仅由最顶层的视图处理。
我希望这对任何人都有帮助。
I had the same problem, but the above solutions did not help.
I then noticed that calling
super.touchesBegan(...)
was the problem.After removing this the event was only handled by the top-most view.
I hope this is of help to anybody.