我有一个视图在许多其他视图的上方重叠。我仅使用这个叠加视图来检测屏幕上的一些点击,但除此之外,我不希望该视图停止底部的其他视图(例如滚动视图等)的行为。如何将所有触摸事件转发到这个叠加视图下面的其他视图?该叠加视图是UIView的子类。
我有一个视图在许多其他视图的上方重叠。我仅使用这个叠加视图来检测屏幕上的一些点击,但除此之外,我不希望该视图停止底部的其他视图(例如滚动视图等)的行为。如何将所有触摸事件转发到这个叠加视图下面的其他视图?该叠加视图是UIView的子类。
禁用用户交互就是我所需要的!
Objective-C:
myWebView.userInteractionEnabled = NO;
Swift:
myWebView.isUserInteractionEnabled = false
myWebView.isUserInteractionEnabled = false
的意思是禁用名为myWebView
的WebView视图的用户交互功能。 - Louis 'LYRO' Dupont为了使覆盖视图下方的视图接收到触摸事件,需要在UIView中实现以下方法:
Objective-C:
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
NSLog(@"Passing all touches to the next view (if any), in the view stack.");
return NO;
}
Swift 5:
->Swift 5:
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
print("Passing all touches to the next view (if any), in the view stack.")
return false
}
这是一篇旧的帖子,但它在搜索中出现了,所以我想加入我的意见。我有一个带有子视图的UIView
,并且 只有希望拦截击中其中一个子视图的触摸事件,因此我修改了PixelCloudSt的答案:
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
for (UIView* subview in self.subviews ) {
if ( [subview hitTest:[self convertPoint:point toView:subview] withEvent:event] != nil ) {
return YES;
}
}
return NO;
}
这是 @fresidue 答案的改进版本。你可以使用这个 UIView
子类作为透明视图,传递触摸事件到其子视图之外。以下是 Objective-C 实现代码:
@interface PassthroughView : UIView
@end
@implementation PassthroughView
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
for (UIView *view in self.subviews) {
if (!view.hidden && [view pointInside:[self convertPoint:point toView:view] withEvent:event]) {
return YES;
}
}
return NO;
}
@end
在Swift中:
class PassthroughView: UIView {
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
return subviews.contains(where: {
!$0.isHidden
&& $0.isUserInteractionEnabled
&& $0.point(inside: self.convert(point, to: $0), with: event)
})
}
}
假设您有一个很大的“容器”面板,可能带有表视图。您可以将“容器”面板设置为PassthroughView
。现在它可以正常工作了,您可以通过“容器”面板滚动表格。
但是!
在“容器”面板上方放置一些标签或图标。当然,别忘了必须将这些标签或图标的用户交互启用关闭!
在“容器”面板顶部添加了一些按钮。当然,别忘了必须将这些按钮的用户交互启用开启!
请注意:有点令人困惑的是,您使用PassthroughView
的“容器”本身必须启用用户交互开启! 是开启!(否则,PassthroughView中的代码将永远不会被调用。)
$0.isUserInteractionEnabled
。 - Sean Thielen我需要通过一个UIStackView传递触摸事件。其中一个UIView是透明的,但UIStackView会消耗所有的触摸事件。以下方法对我有用:
class PassThrouStackView: UIStackView {
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let view = super.hitTest(point, with: event)
if view == self {
return nil
}
return view
}
}
所有arrangedSubviews仍然接收触摸事件,但是对UIStackView本身的触摸事件会穿透到下面的视图(对我来说是地图视图)。
我遇到了一个与UIStackView类似的问题(但可能也适用于其他视图)。
我的配置如下:
在这个经典案例中,我需要将一个容器置于背景中,并在侧边添加按钮。出于布局目的,我将按钮包含在UIStackView中,但现在stackView的中间(空)部分拦截了触摸操作 :-(
我创建了一个UIStackView的子类,其中包含一个属性,定义了应该响应触摸操作的子视图。现在,任何对“viewsWithActiveTouch”数组中的侧边按钮的触摸操作都会传递到按钮上,而在除了这些视图之外的stackview任何其他地方的触摸操作都不会被拦截,因此会传递到位于stack view下面的任何内容。
/** Subclass of UIStackView that does not accept touches, except for specific subviews given in the viewsWithActiveTouch array */
class NoTouchStackView: UIStackView {
var viewsWithActiveTouch: [UIView]?
override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
if let activeViews = viewsWithActiveTouch {
for view in activeViews {
if CGRectContainsPoint(view.frame, point) {
return view
}
}
}
return nil
}
}
如果您希望将触摸事件转发到的视图不是子视图/父视图,您可以在UIView子类中设置自定义属性,如下所示:
@interface SomeViewSubclass : UIView {
id forwardableTouchee;
}
@property (retain) id forwardableTouchee;
@synthesize forwardableTouchee;
然后在任何UIResponder方法中包含以下内容,例如:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self.forwardableTouchee touchesBegan:touches withEvent:event];
}
无论在何处实例化您的UIView,都将forwardableTouchee属性设置为您想要将事件转发到的视图:
SomeViewSubclass *view = [[[SomeViewSubclass alloc] initWithFrame:someRect] autorelease];
view.forwardableTouchee = someOtherView;
在Swift 5中
class ThroughView: UIView {
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
guard let slideView = subviews.first else {
return false
}
return slideView.hitTest(convert(point, to: slideView), with: event) != nil
}
}
看起来虽然这里有很多答案,但没有一个干净的Swift解决我需要的问题。因此,我采用了@fresidue的答案,并将其转换为Swift,因为现在大多数开发人员都想在这里使用它。
它解决了我的问题,其中我有一些带有按钮的透明工具栏,但我希望工具栏对用户不可见,并且触摸事件应该穿过工具栏。
根据我的测试,isUserInteractionEnabled = false不是一个选项。
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
for subview in subviews {
if subview.hitTest(convert(point, to: subview), with: event) != nil {
return true
}
}
return false
}
.isUserInteractionEnabled
表明,如果为false,则视图目标事件将从事件视图中移除,并且显然对于视图的触摸是针对该视图的。 - clearlight我在StackView中有几个标签,但是我并没有成功地使用上面的解决方案,相反,我使用了下面的代码来解决我的问题:
let item = ResponsiveLabel()
// Configure label
stackView.addArrangedSubview(item)
UIStackView的子类化:
class PassThrouStackView:UIStackView{
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
for subview in self.arrangedSubviews {
let convertedPoint = convert(point, to: subview)
let labelPoint = subview.point(inside: convertedPoint, with: event)
if (labelPoint){
return subview
}
}
return nil
}
}
然后你可以这样做:
class ResponsiveLabel:UILabel{
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// Respond to touch
}
}