hit-test的用法总结:如何阻止touch事件传递到子view
来源:互联网 发布:mac电脑查看ip地址 编辑:程序博客网 时间:2024/04/23 17:05
今天,群里有人问了这个问题:添加了touch事件之后怎么阻止touch事件传递到子view。其实看了官方的文档Event Handling Guide for iOS的童鞋,应该是没有问题的。但是自己还是总结一下。
触摸之后,主要的步骤如下:
(1), 事件分发:如何确定当前点击的点由哪个view来处理?
hit-test来确定hit-view
(2), 事件响应:确定hit-view之后,如何处理事件? 当确定了hit-view之后,第一响应者就是当前的hit-view,然后就会根据响应者链来处理触摸事件。
有手势的先处理手势,手势识别失败后,执行touch系列回调处理。
情景应用
问题1:如果父视图userInteractionEnable是NO,这时候子视图能接收touch事件吗?
分析:不能
因为在hit-testing的时候父视图返回nil了,那么就轮不到子视图来hit-testing了。
这也是为何在imgView上面加载UIButton的时候,button无法响应的原因
问题2:如果一个视图A(A上面加载了手势处理)被视图B盖住了,A与B都是视图X的子视图,那么怎样让A的手势能响应?
分析: 因为B盖住了A,所以hit-test的结果之后,hit-view肯定是B,A的手势无法响应,
可以这么做:
1, 设置B.userInteractionEnable = NO;
2, B.hidden = YES;
3, B.alpha = 0;
上面的3种情况下,A都可以响应手势了。
因为这么设置之后,在hit-testing的时候,B视图的hitTest方法返回的是nil,最终的hit-view是A,所以触摸事件就轮到了A来处理。
问题3:如果一个viewA不希望它的subView来处理touch事件,而是由自己处理,怎么办?
分析:
viewA不希望触摸事件传递到它的subView, 也就是viewA自己阻断触摸事件的传递,只要让触摸后最终的hit-view是他自己就可以了。
比如viewA的subView为YLViewSub1
有如下2种方法:
方法一:不推荐
在viewA的.m文件中重载hitTest(注意:viewA是一个自定义的UIView才能重载此方法),如下
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
{
UIView *hitView = [super hitTest:pointwithEvent:event];
//此时hitView是已经检测出的hit-view了,是self or subViews(hitted subView)
/*注意:
* 如果想要阻断触摸事件传递给subView,下面的2种做法是不太合理的:
*/
/* 方法1:
*不管3721的直接返回self也是不对的,因为当没有点击在self上(包括它的subView)的时候,self都成了hit-view
*/
return self;
*/
return self;
/* 方法2:
*因为hitView可能返回的是它的subView的subView的subView...
* 所以不能这么做.如果能确定self的subView只有一级,这么做也是可以的.
*/
if (hitView.superview == self && hitView ==self) {
return self;// 点击在它的subView上也由它自己来处理,subView永远不是hit-view(永远不会是第一响应者,不处理触摸)
}
* 所以不能这么做.如果能确定self的subView只有一级,这么做也是可以的.
*/
if (hitView.superview == self && hitView ==self) {
return self;// 点击在它的subView上也由它自己来处理,subView永远不是hit-view(永远不会是第一响应者,不处理触摸)
}
/* 正确的做法:也就是下面的方法二,在subView中重载hitTest
* 1,可以在self的subView中重载hitTest方法,直接返回nil,那么点击在self的subView上的时候,最后hit-view还是self
* 所以在重载此方法的时候一定要搞清楚具体的应用场景.
*/
return nil;
* 所以在重载此方法的时候一定要搞清楚具体的应用场景.
*/
return nil;
}
可以看到直接在viewA中重载还是不太好的实现,而且如果viewA是一个vc.view,那么就没办法重载hitTest方法了。
方法二:推荐
在viewA的subView(YLViewSub1)的类中重载hitTest,
在YLViewSub1的.m文件中,
-(id)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
UIView *hitView = [super hitTest:pointwithEvent:event];
{
UIView *hitView = [super hitTest:pointwithEvent:event];
if (hitView ==self) {
return nil;
} else {
return hitView;
return nil;
} else {
return hitView;
}
}
有人可能有疑问了:上面说过直接在这里返回nil不就可以了,为什么还要分情况处理。
其实这要看具体的情况了,如果YLViewSub1上面还有subView,直接的返回nil,那么就会忽略掉,所以如果你想全部忽略掉就直接返回nil,不然可以像上面这么处理。
另外,还有一种更简单的做法,直接让viewA的subView的userInteraction为NO,那么subView就不会受到触摸消息了。
扩展:
hit-test还有另外一个场景,比如viewA有B,C两个subView,但是他们2个有重合的部分,点击重合部分,那如何指定让B响应还是C来响应。
分析:
默认情况下,hit-test的时候,是从subViews的最顶上的subView开始执行hit-test,即假如先加B,再加载C,那么hit-test就是先C先B后,这样点击重合部分,那就是C就是hit-view,那么由C来响应。
如何变成让B先响应呢?
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
UIView *hitView = [super hitTest:pointwithEvent:event];
{
UIView *hitView = [super hitTest:pointwithEvent:event];
if (hitView == viewC) {// 点击在C上的时候,让hit-view为B,那么B就是第一响应者
return viewB;
} else {
return hitView;
}
} else {
return hitView;
}
}
这样,当点击重合部分就由B响应,点击B,C非重合部分由他们各自响应.
问题4:如果一个view自己不愿意处理touch事件,但是希望它的subViews处理,怎么办?
应用场景:这个问题有点sb,因为默认情况下就是subView来先处理,应用场景在哪?
可能是如果点击view自己,让他的父视图处理,点击view上面的subView由subView响应更合理?
分析:
设置view.userInteractionEnable = NO;之后,虽然自己不会响应touch事件,但是它的子view也不会响应了,
所以不能这么做。这时候就需要使用hitTest来处理,
-( UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
UIView *hitView = [super hitTest:point withEvent:event];
if (hitView == self) {
return nil; // 是self的时候, 不做处理,由它的父视图处理
} else {
return hitView; // 是subView的时候,由subView去处理
}
}
return hitView; // 是subView的时候,由subView去处理
}
}
问题5:如果一个view自己不想处理,也不愿意往它的响应者链传递让别人处理,怎么办?
分析:首先,确定处理对象的时候必须是自己,然后,在自己这里处理的时候丢弃,
也就是自己重载响应函数,然后响应函数里面不做任何事,这样就不会继续向上传递了,也就是在自己这里做一个空处理来截止响应的处理.
问题6:一个全屏的UIView上加载了tap手势,在此view上加载一个UITableView,点击cell的时候没有执行tableview的didSelected:方法,而是响应了_onTap手势,如何处理?
解决方法:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
// tianyi memo:
//点击在tableView上时,因为tableView自己不响应tap,所以会交给它的父视图self来响应,也就是响应_onTap:,但这不是我们想要的
//我们需要点击tableView上面时,响应tableView的didSelectRowAtIndexPath方法.点击其他空白地方相应_onTap:
//返回NO表示,tap手势不会根据响应者链传递了,当前的touch对象会被忽略,也就是丢弃这个手势,
//丢弃手势之后,相当于手势识别失败,然后就会走默认的touch系列回调方法,我猜测在这个时候UITableView执行了自己默认的选择cell的流程.
if ([touch.viewisDescendantOfView:_tableView]) {
returnNO;
}
{
// tianyi memo:
//点击在tableView上时,因为tableView自己不响应tap,所以会交给它的父视图self来响应,也就是响应_onTap:,但这不是我们想要的
//我们需要点击tableView上面时,响应tableView的didSelectRowAtIndexPath方法.点击其他空白地方相应_onTap:
//返回NO表示,tap手势不会根据响应者链传递了,当前的touch对象会被忽略,也就是丢弃这个手势,
//丢弃手势之后,相当于手势识别失败,然后就会走默认的touch系列回调方法,我猜测在这个时候UITableView执行了自己默认的选择cell的流程.
if ([touch.viewisDescendantOfView:_tableView]) {
returnNO;
}
returnYES;
}
如果有不正确或者考虑不完善的地方,欢迎指正交流。
0 0
- hit-test的用法总结:如何阻止touch事件传递到子view
- 关于hit-test用法,视图事件传递链的控制
- **深入浅出的事件路由(view hit test)**
- iOS事件响应链中Hit-Test View的应用
- iOS事件响应链中Hit-Test View的应用
- iOS事件响应链中Hit-Test View的应用
- 如何屏蔽父view的touch事件到,并且响应self的touch
- Android Touch事件传递的一些总结
- iOS学习笔记73-iOS事件响应链中Hit-Test View的应用
- Cocos2dx Lua 关于Touch事件传递阻止下层传递的问题
- View事件传递 touch事件分发
- Android - requestDisallowInterceptTouchEvent() 阻止父层的View截获touch事件(事件处理机制)
- Android中view的Touch事件传递顺序
- 深入探索Android 中view的touch事件传递
- Android touch事件传递及View的绘制流程
- View的touch事件
- touch事件传递原理总结
- touch事件传递原理总结
- javascript数组取值
- Environment Tree(环境树)
- hdu 5281 Senior's Gun(贪心)(思维)
- Dalvik虚拟机异常处理机制
- jsp 超链接跳转 弹出框提示是否操作
- hit-test的用法总结:如何阻止touch事件传递到子view
- 2016的路程--写给自己
- Android.mk文件分析
- Android 深入理解Android中的自定义属性
- 几个画图的js插件
- iOS开发:初识xib
- IOS-设备屏幕及适配方案
- python爬虫+mongoDB存储DOTA2比赛数据总结
- jquery的$().each,$.each的区别