我有一个视图叠加在许多其他视图之上。我只是使用过度的方法来检测屏幕上的一些触摸,但除此之外我不希望视图停止下面其他视图的行为,这些是滚动视图等。我怎样才能转发所有的触摸通过这个叠加视图?这是UIView的一个主要内容。
答案 0 :(得分:101)
要将覆盖视图中的触摸传递到下面的视图,请在UIView中实现以下方法:
目标-C:
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
NSLog(@"Passing all touches to the next view (if any), in the view stack.");
return NO;
}
夫特:
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
}
答案 1 :(得分:89)
myWebView.userInteractionEnabled = NO;
就是我所需要的一切!
答案 2 :(得分:50)
这是一个老线程,但它出现在搜索中,所以我想我会添加我的2c。我有一个覆盖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;
}
答案 3 :(得分:29)
@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.point(inside: self.convert(point, to: $0), with: event)
})
}
}
答案 4 :(得分:6)
我需要通过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本身的触摸进入了下面的视图(对我来说是mapView)。
答案 5 :(得分:5)
如果要转发的视图不是子视图/超级视图,则可以在UIView子类中设置自定义属性,如下所示:
@interface SomeViewSubclass : UIView {
id forwardableTouchee;
}
@property (retain) id forwardableTouchee;
确保在.m中合成它:
@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;
答案 6 :(得分:5)
我遇到了与UIStackView类似的问题(但可能是任何其他视图)。 我的配置如下:
这是一个经典案例,我有一个需要放在背景中的容器,侧面有按钮。出于布局目的,我在UIStackView中包含了按钮,但现在stackView的中间(空)部分拦截了触摸: - (
我所做的是创建一个UIStackView的子类,其中一个属性定义了应该可触摸的subView。 现在,对侧按钮(包含在* viewsWithActiveTouch *数组中)的任何触摸都将被赋予按钮,而除了这些视图之外的任何其他地方的任何触摸都不会被拦截,因此传递给下面的任何内容堆栈视图。
/** 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
}
}
答案 7 :(得分:0)
尝试这样的事情......
for (UIView *view in subviews)
[view touchesBegan:touches withEvent:event];
上面的代码,例如在你的touchesBegan方法中,会将触摸传递给所有视图的子视图。
答案 8 :(得分:0)
在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
}
}
答案 9 :(得分:0)
即使您在这里看起来也有很多答案,但我所需要的并没有那么迅速。 所以我从这里的@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
}
答案 10 :(得分:0)
我在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
}
}
答案 11 :(得分:0)
我要尝试的情况是使用嵌套的UIStackView内部的控件来构建控制面板。一些控件具有UITextField的其他控件和UIButton的控件。此外,还有用于标识控件的标签。我想做的是在控制面板后面放一个大的“不可见”按钮,这样,如果用户在按钮或文本字段之外的区域上轻按,我就可以接住并采取行动-如果出现文本,则首先关闭任何键盘字段处于活动状态(resignFirstResponder)。但是,在控制面板上点击标签或其他空白区域不会使任何东西通过。以上讨论有助于在下面提出我的答案。
基本上,我将UIStackView子类化,并重写“ point(inside:with)例程”以查找需要触摸的控件类型,并“忽略”我想忽略的标签之类的东西。它还会检查UIStackView的内部内容,以便可以将其递归到控制面板结构中。
该代码可能比它应有的冗长。但这对调试很有帮助,希望可以使例程的工作更加清晰。只需确保在Interface Builder中将UIStackView的类更改为PassThruStack。
class PassThruStack: UIStackView {
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
for view in self.subviews {
if !view.isHidden {
let isStack = view is UIStackView
let isButton = view is UIButton
let isText = view is UITextField
if isStack || isButton || isText {
let pointInside = view.point(inside: self.convert(point, to: view), with: event)
if pointInside {
return true
}
}
}
}
return false
}
}
答案 12 :(得分:-1)
正如@PixelCloudStv所建议的那样,如果你想从一个视图到另一个视图,但是对这个过程有一些额外的控制 - 子类UIView
//头
@interface TouchView : UIView
@property (assign, nonatomic) CGRect activeRect;
@end
//实施
#import "TouchView.h"
@implementation TouchView
#pragma mark - Ovverride
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
BOOL moveTouch = YES;
if (CGRectContainsPoint(self.activeRect, point)) {
moveTouch = NO;
}
return moveTouch;
}
@end
在interfaceBuilder之后,只需将View类设置为TouchView,并使用rect设置活动rect。你也可以改变并实现其他逻辑。
答案 13 :(得分:-3)
在 Swift 4.0 及更高版本中进行的更新对我来说很有效:
myWebView.isUserInteractionEnabled = false;