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

sol*_*sol 125 events touch uiview

我有一个视图叠加在许多其他视图之上.我只是使用过度的方法来检测屏幕上的一些触摸,但除此之外我不希望视图停止下面其他视图的行为,这些是滚动视图等.我怎样才能转发所有的触摸通过这个叠加视图?它是UIView的子项.

Pix*_*dSt 105

要将覆盖视图中的触摸传递到下面的视图,请在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;
}
Run Code Online (Sandbox Code Playgroud)

迅速:

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
}
Run Code Online (Sandbox Code Playgroud)

  • 我有同样的问题,但我想要的是如果我用手势缩放/旋转/移动视图然后它应该返回是和休息事件它应该返回否,我怎么能实现这一点? (3认同)

rmp*_*251 105

myWebView.userInteractionEnabled = NO;
Run Code Online (Sandbox Code Playgroud)

就是我所需要的一切!

  • 在Swift 4中,`myWebView.isUserInteractionEnabled = false` (2认同)

fre*_*due 52

这是一个旧线程,但它出现在搜索上,所以我想我会添加我的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;
}
Run Code Online (Sandbox Code Playgroud)


Tim*_*ich 34

@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
Run Code Online (Sandbox Code Playgroud)

斯威夫特:

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)
    })
  }
}
Run Code Online (Sandbox Code Playgroud)


小智 10

我需要通过 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
    }
}
Run Code Online (Sandbox Code Playgroud)

所有排列的子视图仍然接收触摸,但对 UIStackView 本身的触摸会传递到下面的视图(对我来说是一个 mapView)。


Chr*_*add 6

如果要转发的视图不是子视图/超级视图,则可以在UIView子类中设置自定义属性,如下所示:

@interface SomeViewSubclass : UIView {

    id forwardableTouchee;

}
@property (retain) id forwardableTouchee;
Run Code Online (Sandbox Code Playgroud)

确保在你的.m中合成它:

@synthesize forwardableTouchee;
Run Code Online (Sandbox Code Playgroud)

然后在您的任何UIResponder方法中包含以下内容,例如:

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

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

}
Run Code Online (Sandbox Code Playgroud)

无论您在何处实例化UIView,都要将forwardableTouchee属性设置为您要将事件转发到的任何视图:

    SomeViewSubclass *view = [[[SomeViewSubclass alloc] initWithFrame:someRect] autorelease];
    view.forwardableTouchee = someOtherView;
Run Code Online (Sandbox Code Playgroud)


Fré*_*dda 6

我有一个与UIStackView类似的问题(但可能是任何其他视图).我的配置如下: 使用containerView和StackView查看控制器

这是一个经典案例,我有一个需要放在背景中的容器,侧面有按钮.出于布局目的,我在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
   }
}
Run Code Online (Sandbox Code Playgroud)


onm*_*133 5

在斯威夫特 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
    }
}
Run Code Online (Sandbox Code Playgroud)


Ren*_*tik 5

看起来即使你这里有很多答案,但没有一个是我需要的快速干净的。所以我在这里接受了 @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
}
Run Code Online (Sandbox Code Playgroud)


Jor*_*dan 0

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

for (UIView *view in subviews)
  [view touchesBegan:touches withEvent:event];
Run Code Online (Sandbox Code Playgroud)

例如,上面的代码在您的 TouchesBegan 方法中会将触摸传递给视图的所有子视图。

  • 据我所知,这种方法的问题是尝试将触摸转发到 UIKit 框架的类通常不会产生任何效果。根据 Apple 的文档,UIKit 框架类并非旨在接收将 view 属性设置为其他视图的触摸。所以这种方法主要适用于 UIView 的自定义子类。 (7认同)