ios 如何单击透明 UIView 后面的按钮?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3046813/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I click a button behind a transparent UIView?
提问by Sean Clark Hess
Let's say we have a view controller with one sub view. the subview takes up the center of the screen with 100 px margins on all sides. We then add a bunch of little stuff to click on inside that subview. We are only using the subview to take advantage of the new frame ( x=0, y=0 inside the subview is actually 100,100 in the parent view).
假设我们有一个带有一个子视图的视图控制器。子视图占据屏幕的中心,所有边都有 100 像素的边距。然后我们添加一堆小东西来点击那个子视图。我们只是使用子视图来利用新框架(子视图中的 x=0, y=0 实际上是父视图中的 100,100)。
Then, imagine that we have something behind the subview, like a menu. I want the user to be able to select any of the "little stuff" in the subview, but if there is nothing there, I want touches to pass through it (since the background is clear anyway) to the buttons behind it.
然后,想象我们在子视图后面有一些东西,比如菜单。我希望用户能够选择子视图中的任何“小东西”,但如果那里没有任何东西,我希望触摸通过它(因为背景很清楚)到它后面的按钮。
How can I do this? It looks like touchesBegan goes through, but buttons don't work.
我怎样才能做到这一点?看起来 touchesBegan 通过了,但按钮不起作用。
回答by John Stephen
Create a custom view for your container and override the pointInside: message to return false when the point isn't within an eligible child view, like this:
为您的容器创建自定义视图并覆盖 pointInside: 消息以在该点不在符合条件的子视图中时返回 false,如下所示:
Swift:
迅速:
class PassThroughView: UIView {
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
for subview in subviews {
if !subview.isHidden && subview.isUserInteractionEnabled && subview.point(inside: convert(point, to: subview), with: event) {
return true
}
}
return false
}
}
Objective C:
目标 C:
@interface PassthroughView : UIView
@end
@implementation PassthroughView
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
for (UIView *view in self.subviews) {
if (!view.hidden && view.userInteractionEnabled && [view pointInside:[self convertPoint:point toView:view] withEvent:event])
return YES;
}
return NO;
}
@end
Using this view as a container will allow any of its children to receive touches but the view itself will be transparent to events.
将此视图用作容器将允许其任何子项接收触摸,但视图本身对事件是透明的。
回答by akw
I also use
我也用
myView.userInteractionEnabled = NO;
No need to subclass. Works fine.
无需子类化。工作正常。
回答by Hymanslash
Event forwarding is a technique used by some applications. You forward touch events by invoking the event-handling methods of another responder object. Although this can be an effective technique, you should use it with caution. The classes of the UIKit framework are not designed to receive touches that are not bound to them .... If you want to conditionally forward touches to other responders in your application, all of these responders should be instances of your own subclasses of UIView.
事件转发是一些应用程序使用的一种技术。您可以通过调用另一个响应者对象的事件处理方法来转发触摸事件。虽然这可能是一种有效的技术,但您应该谨慎使用它。UIKit 框架的类不是设计来接收未绑定到它们的触摸......如果你想有条件地将触摸转发给应用程序中的其他响应者,所有这些响应者都应该是你自己的 UIView 子类的实例。
Do not explicitly send events up the responder chain (via nextResponder); instead, invoke the superclass implementation and let the UIKit handle responder-chain traversal.
不要在响应者链上显式发送事件(通过 nextResponder);相反,调用超类实现并让 UIKit 处理响应者链遍历。
instead you can override:
相反,您可以覆盖:
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
in your UIView subclass and return NO if you want that touch to be sent up the responder chain (I.E. to views behind your view with nothing in it).
在您的 UIView 子类中,如果您希望将触摸发送到响应者链(IE 到您的视图后面没有任何内容的视图),则返回 NO。
回答by Tod Cunningham
Building on what John posted, here is an example that will allow touch events to pass through all subviews of a view except for buttons:
基于 John 发布的内容,这里有一个示例,它允许触摸事件通过视图的所有子视图,但按钮除外:
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
// Allow buttons to receive press events. All other views will get ignored
for( id foundView in self.subviews )
{
if( [foundView isKindOfClass:[UIButton class]] )
{
UIButton *foundButton = foundView;
if( foundButton.isEnabled && !foundButton.hidden && [foundButton pointInside:[self convertPoint:point toView:foundButton] withEvent:event] )
return YES;
}
}
return NO;
}
回答by Segev
Lately I wrote a class that will help me with just that. Using it as a custom class for a UIButton
or UIView
will pass touch events that were executed on a transparent pixel.
最近我写了一个课程来帮助我解决这个问题。将其用作UIButton
或UIView
将传递在透明像素上执行的触摸事件的自定义类。
This solution is a somewhat better than the accepted answer because you can still click a UIButton
that is under a semi transparent UIView
while the non transparent part of the UIView
will still respond to touch events.
此解决方案比接受的答案要好一些,因为您仍然可以单击UIButton
半透明下的 a,UIView
而 的非透明部分UIView
仍将响应触摸事件。
As you can see in the GIF, the Giraffe button is a simple rectangle but touch events on transparent areas are passed on to the yellow UIButton
underneath.
正如您在 GIF 中看到的,Giraffe 按钮是一个简单的矩形,但透明区域上的触摸事件会传递到UIButton
下方的黄色。
回答by Jeff
回答by PakitoV
Top voted solution was not fully working for me, I guess it was because I had a TabBarController into the hierarchy (as one of the comments points out) it was in fact passing along touches to some parts of the UI but it was messing with my tableView's ability to intercept touch events, what finally did it was overriding hitTestin the view I want to ignore touches and let the subviews of that view handle them
最高投票的解决方案对我来说并不完全适用,我想这是因为我在层次结构中有一个 TabBarController(正如其中一条评论指出的那样)它实际上是将触摸传递到 UI 的某些部分,但它弄乱了我的tableView 拦截触摸事件的能力,它最终在视图中覆盖了hitTest我想忽略触摸并让该视图的子视图处理它们
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
UIView *view = [super hitTest:point withEvent:event];
if (view == self) {
return nil; //avoid delivering touch events to the container view (self)
}
else{
return view; //the subviews will still receive touch events
}
}
回答by Barath
Swift 3
斯威夫特 3
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
for subview in subviews {
if subview.frame.contains(point) {
return true
}
}
return false
}
回答by LK.
According to the 'iPhone Application Programming Guide':
根据“iPhone应用程序编程指南”:
Turning off delivery of touch events. By default, a view receives touch events, but you can set its userInteractionEnabled property to NO to turn off delivery of events. A view also does not receive events if it's hidden or if it's transparent.
关闭触摸事件的传递。默认情况下,视图接收触摸事件,但您可以将其 userInteractionEnabled 属性设置为 NO 以关闭事件传递。如果视图是 hidden 或者是 transparent ,它也不会接收事件。
Updated: Removed example - reread the question...
更新:删除示例 - 重读问题...
Do you have any gesture processing on the views that may be processing the taps before the button gets it? Does the button work when you don't have the transparent view over it?
在按钮获取之前,您是否对可能正在处理点击的视图进行了任何手势处理?当您没有透明视图时,该按钮是否有效?
Any code samples of non-working code?
任何非工作代码的代码示例?
回答by Liam
As far as I know, you are supposed to be able to do this by overriding the hitTest:method. I did try it but could not get it to work properly.
据我所知,您应该能够通过覆盖hitTest:方法来做到这一点。我确实尝试过,但无法使其正常工作。
In the end I created a series of transparent views around the touchable object so that they did not cover it. Bit of a hack for my issue this worked fine.
最后,我在可触摸对象周围创建了一系列透明视图,以便它们不会覆盖它。对我的问题有点破解,这很好用。