subview在SuperView的bounds之外接收触摸信息。以及subview的响应

来源:互联网 发布:手机淘宝我的店铺 编辑:程序博客网 时间:2024/05/22 05:09

subview在SuperView的bounds之外接收触摸信息。以及subview的响应

先简要说明一下我遇到的问题。当一个button,或者其他的subview显示在它的superview的bounds之外,如果你不做任何更改的情况下,会发现点击这个subview是没有任何响应事件的。
所以duang的一下,我要研究的地方来了。subview到底在什么条件下才会响应触摸事件呢?

首先去查看了下关于响应的文档,查到了关于响应UIView所提供的方法hitTest:withEvent:

Points that lie outside the receiver’s bounds are never reported as hits, even if they actually lie within one of the receiver’s subviews. This can occur if the current view’s clipsToBounds property is set to NO and the affected subview extends beyond the view’s bounds.。

翻译过来就是:

在当前view的bounds之外的触摸永远不会被接收,即使它是当前view的subview。当你把当前view的clipToBounds属性设置成false,并且把subView移动到当前view的bounds之外的时候,这种情况就会出现。

这里又要说一下clipToBounds

@property(nonatomic) BOOL clipsToBounds; // When YES, content and subviews are clipped to the bounds of the view. Default is NO.
默认是NO,当它为yes时,你超出superView的Bounds的subview就不会显示了哦

所以说在一般情况下。你的touch事件会被限制在view的frame内。如果touch事件是发生在当前view的frame以外,该view所有的subview,包括它本身将也不会再收到该消息

但是我们就是要固执的实现我的subview在superView的bounds外,我还要它能响应touch事件。怎么破?这是我们关心的。

这就要我们刚才所说的hitTest来搞了。先说一下hitTest的原理:

UIView的对于触摸的响应链是从下到上的。hitTest是从UIWindow->UIViewController->UIVIew一层一层找First Responder的过程,默认来说,这个方法默认会返回在自己bounds之内的subView或者subViewController(同时ALPHA > 0.01并且hidden = false)。

啦啦啦。改写这个方法当然就可以让查找的过程处于bounds之外的View同样能成为firstResponder。

 -(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{       if (!self.clipsToBounds && !self.hidden && self.alpha > 0) {        for (UIView *subview in self.subviews.reverseObjectEnumerator) {            CGPoint subPoint = [subview convertPoint:point fromView:self];            UIView *result = [subview hitTest:subPoint withEvent:event];            if (result != nil) {                return result;            }        }    }    return nil;}

来自 http://stackoverflow.com/questions/11770743/capturing-touches-on-a-subview-outside-the-frame-of-its-superview-using-hittest/14875673#14875673

下面我写一个例子来实际的看一下这个情况
首先是自定义一个view,要继承UIView哦。要不怎么重写方法。吼吼

#import <UIKit/UIKit.h>@interface UITestView : UIView@end
@implementation UITestView- (id)initWithFrame:(CGRect)frame{    self = [super initWithFrame:frame];    if (self) {        // Initialization code        self.backgroundColor = [UIColor redColor];        UIButton *testOutBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect];        testOutBtn.frame = CGRectMake(-80, -50, 70, 30);        [testOutBtn addTarget:self action:@selector(btnAction:) forControlEvents:UIControlEventTouchUpInside];        [testOutBtn setTitle:@"I'm out" forState:UIControlStateNormal];        [self addSubview:testOutBtn];        UIButton *testInBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect];        testInBtn.frame = CGRectMake(20, 30, 70, 30);        [testInBtn setTitle:@"I'm in" forState:UIControlStateNormal];        [testInBtn addTarget:self action:@selector(btnAction:) forControlEvents:UIControlEventTouchUpInside];        [self addSubview:testInBtn];//        self.clipsToBounds = YES;//        self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;    }    return self;}- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{    if (!self.clipsToBounds && !self.hidden && self.alpha > 0) {        for (UIView *subview in self.subviews.reverseObjectEnumerator) {            CGPoint subPoint = [subview convertPoint:point fromView:self];            UIView *result = [subview hitTest:subPoint withEvent:event];            if (result != nil) {                return result;            }        }    }    return nil;}/* // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code } */- (void)btnAction:(UIButton*)sender{    NSLog(@"you tap button");}

在你的程序的ViewController中添加如下代码

UITestView *testSubView = [[UITestView alloc] initWithFrame:CGRectMake(100, 100, 150, 150)];[self.view addSubview:testClipSubView];

可以改一下self.clipsToBounds。看看不同的的效果。

0 0
原创粉丝点击