iOS - 通过视图转发所有触摸


75

我有覆盖在许多其他视图之上的视图。我只使用这个方法来检测屏幕上的某些触摸,但除此之外,我不希望视图停止其他视图的行为,这些视图是滚动视图等。如何将所有触摸转发这个覆盖视图?它是UIView的一个subcalss。

0

尝试这样的事情......

for (UIView *view in subviews) 
    [view touchesBegan:touches withEvent:event]; 

上面的代码中,例如您的touchesBegan方法会通过触摸到所有的观点的子视图。

+6

这种方法AFAIK的问题是,试图触摸转发给UIKit框架中的类将最经常没有影响。根据Apple的文档,UIKit框架类不能用于接收将视图属性设置为其他视图的触摸。所以这种方法主要用于UIView的自定义子类。 02 3月. 112011-03-02 23:05:35


4

如果你要转发的触摸视图,以不正好是一个子视图/上海华盈,你可以设置自定义属性在你的UIView子类,像这样:

@interface SomeViewSubclass : UIView { 

    id forwardableTouchee; 

} 
@property (retain) id forwardableTouchee; 

确保合成它在您的m:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 

    [self.forwardableTouchee touchesBegan:touches withEvent:event]; 

} 

@synthesize forwardableTouchee; 

,然后再向您的任何UIResponder方法,如下面的

无论你实例化你的UIView,设置forwardableTouchee属性无论大家认为你想将事件转发到:

SomeViewSubclass *view = [[[SomeViewSubclass alloc] initWithFrame:someRect] autorelease]; 
    view.forwardableTouchee = someOtherView; 

75

对于从覆盖视图传递触摸到的意见下,实现以下方法了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 
} 
+2

我有同样的问题,但我想要的是,如果我用手势缩放/旋转/移动视图,那么它应该返回yes,对于休息事件,它应该返回no,我该如何实现? 12 8月. 132013-08-12 06:27:33


58
myWebView.userInteractionEnabled = NO; 

是我所需要的!


38

这是一个旧线程,但它出现在搜索中,所以我想我会添加我的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; 
} 
+1

您需要创建一个自定义的UIView子类(或任何其他UIView子类的子类,例如UIImageView或其他)并覆盖此函数。本质上,子类在.h文件中可以有一个完全空的'@interface',上面的函数是'@implementation'的全部内容。 07 3月. 142014-03-07 16:01:14


-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设置为活动矩形。你也可以改变和实现其他逻辑。


3

我有一个与UIStackView类似的问题(但可以是任何其他视图)。 我的配置是如下: View controller with containerView and StackView

这就是我有一个需要被放置在后台,与上侧的按钮的容器中的情况下,经典。为了布局的目的,我在UIStackView中包含了这些按钮,但是现在stackView的中间(空)部分拦截了触摸:-(

我所做的是创建一个UIStackView的子类,该子类定义了应该是子视图的属性可触摸 现在,任何触摸按钮(包含在* 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 
    } 
} 

14

改进版@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 

斯威夫特:

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) 
    }) 
    } 
}