Events iOS-通过视图转发所有接触

Events iOS-通过视图转发所有接触,events,uiview,touch,Events,Uiview,Touch,我有一个覆盖在许多其他视图之上的视图。我只使用overaly来检测屏幕上的一些触摸次数,但除此之外,我不希望视图停止下面其他视图的行为,这些视图是滚动视图等。如何通过此覆盖视图转发所有触摸?这是UIView的子脚本。试试这样的东西 for (UIView *view in subviews) [view touchesBegan:touches withEvent:event]; 例如,上面的代码在touchesBegind方法中会将触摸传递给视图的所有子视图。如果要将触摸转发到的视图恰好

我有一个覆盖在许多其他视图之上的视图。我只使用overaly来检测屏幕上的一些触摸次数,但除此之外,我不希望视图停止下面其他视图的行为,这些视图是滚动视图等。如何通过此覆盖视图转发所有触摸?这是UIView的子脚本。

试试这样的东西

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

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

如果要将触摸转发到的视图恰好不是子视图/超级视图,可以在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;

要将接触从覆盖视图传递到下面的视图,请在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;
}
myWebView.userInteractionEnabled = NO;
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
}

禁用用户交互是我所需要的

目标C:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    NSLog(@"Passing all touches to the next view (if any), in the view stack.");
    return NO;
}
myWebView.userInteractionEnabled = NO;
斯威夫特:

myWebView.isUserInteractionEnabled = false

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

正如@PixelCloudStv所建议的,如果您想将touch从一个视图切换到另一个视图,但需要对该过程进行一些额外的控制-子类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后,只需将视图类设置为TouchView,并使用您的rect设置活动rect。您还可以更改和实现其他逻辑。

我在UIStackView中遇到了类似的问题(但可能是任何其他视图)。 我的配置如下:

这是一个典型的例子,我有一个容器,需要放在背景中,旁边有按钮。出于布局目的,我在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
   }
}

@fresidue answer的改进版本。您可以使用此
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)
    })
  }
}

提示: 假设你有一个大的“holder”面板,可能后面有一个表视图。你可以使“holder”面板
通过视图
。现在它可以工作了,你可以在“holder”中滚动表格

但是

  • 在“支架”面板的顶部有一些标签或图标。别忘了,当然,这些标签或图标必须简单地标记为“用户交互启用关闭”

  • 在“支架”面板的顶部有一些按钮。别忘了,当然这些按钮必须简单地标记为启用用户交互

  • 注意有点令人困惑的是,“持有者”本身-您在上使用的视图
    PassthroughView
    on-必须在上标记为启用了用户交互功能!这是on!!(否则,将永远不会调用PassthroughView中的代码。)

  • 斯威夫特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
        }
    }
    

    看起来,即使是你,这里也有很多答案,没有一个干净的斯威夫特,我需要的。 所以我在这里从@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
    }
    

    我在StackView中有两个标签,我在上面的解决方案中没有太大成功,相反,我使用以下代码解决了我的问题:

        let item = ResponsiveLabel()
    
        // Configure label
    
        stackView.addArrangedSubview(item)
    
    子类化视图:

    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
        }
    }
    
    类响应标签:UILabel{
    覆盖func TouchesBegind(Touchs:Set,带有事件:UIEvent?){
    //对触摸作出反应
    }
    }
    
    我试图使用嵌套的UIStackView中的控件构建一个控制面板。一些控件有UITextField的控件,其他控件有UIButton的控件。此外,还有标识控件的标签。我想做的是放一个大的“不可见”图标控制面板后面的按钮,这样,如果用户点击按钮或文本字段外的区域,我就可以捕捉到并采取行动-如果文本字段处于活动状态,主要是关闭任何键盘(辞职FirstResponder)。但是,轻敲控制面板上的标签或其他空白区域不会传递任何信息。上述讨论有助于我在下面给出答案

    基本上,我对UIStackView进行了子分类,并重写了“point(inside:with)”例程,以查找需要触摸的控件类型,以及“忽略”我想要忽略的标签之类的内容。它还检查UIStackView内部的内容,以便这些内容可以递归到控制面板结构中

    代码可能比它应该的要详细一点。但它在调试中很有帮助,并且希望能够更清楚地说明例程正在执行的操作。只需确保在Interface Builder中将UIStackView的类更改为PassTrustPack即可

    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
    }
    

    }

    我需要通过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
        }
    }
    
    所有ArrangedSubview仍会接收到触摸,但UIStackView本身上的触摸会消失