关于hit-testing机制
来源:互联网 发布:七天网络查分网页登陆 编辑:程序博客网 时间:2024/05/16 17:43
当我们点击屏幕上某个点的时候, IOS会检查到手指触摸操作(Touch),并生产一个UITouch对象,将其打包成一个UIEvent对象。然后将其放入当前活动的Application的 事件对列 , UIApplication会从 事件对列 中按照对列的顺序,通常先分发给应用程序主窗口,主窗口会调用hitTest:withEvent:方法(假设称为方法A,注意这是UIView的方法),查找合适的事件触发视图(这里通常称为“hit-test view”)。
看下面的图就一目了然
关于方法- hitTest withEvent:
主要原理是:
若某个类重写了 hitTest 方法,该方法会先判断
1.是否满足以下三种情况,
self.userInteractionEnabled = NO
self.hidden = YES
self.alpha <= 0.01
这三种情况时当前视图就不再接收消息了,直接返回 nil。
2.判断触摸点是否在该类范围内,若pointInside返回 YES就倒序遍历 subview,subView 调用自己的 hit 方法,一层subview一层subview 的找下去,若最终找到一个目标 view,该类的 hit 方法就返回这个 目标view,若没有这个 view,则返回 self。若pointInside返回 NO 返回 nil。
上代码:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { if (!self.isUserInteractionEnabled || self.isHidden || self.alpha <= 0.01) { return nil; } if ([self pointInside:point withEvent:event]) { for (UIView *subview in [self.subviews reverseObjectEnumerator]) { CGPoint convertedPoint = [subview convertPoint:point fromView:self]; UIView *hitTestView = [subview hitTest:convertedPoint withEvent:event]; if (hitTestView) { return hitTestView; } } return self; } return nil;}
首先MainView 上的子view包括 viewA,ViewB(ViewB1,ViewB2),ViewC,添加顺序也是依次添加。
由图和代码我们可以看出:遍历当前视图的所有子视图的顺序是从当前视图的subviews数组的末尾向前遍历(倒序),即先判断最后添加到当前视图上的子视图
下面是整个触摸的传递过程,传递到不同的 View 调用- hitTest withEvent:判断触摸点是否在当前视图范围内
1.主 window:-pointInside: withEvent:–>return YES,以此为根节点向下进行倒序遍历搜索
2.MainView :-pointInside: withEvent:–>return YES,以此为根节点向下进行倒序遍历搜索
3.ViewC:-pointInside: withEvent:–>return NO,不再向下进行搜索
4.ViewB :-pointInside: withEvent:–> YES,以此为根节点向下进行搜索
5.ViewB2 :–> NO,不再向下进行搜索
6.ViewB1 :–> YES,好了到这 ViewB2没有子视图(或者子视图的 hitView 都返回了nil),直接返回 self
至此,我们已经找到了 hitView,接下来把 hitView 向上传递给 UIApplication,UIApplication中有个sendEvent:的方法,在UIWindow中同样也可以发现一个同样的方法。UIApplication是通过这个方法把事件发送给UIWindow,然后UIWindow通过同样的接口,把事件发送给hit-testview,此时hitView会调用touchesBegan方法响应事件
下面来看几种情况:
1.当前view,包括子 view 都不接收事件,将事件传递给兄弟viewA:当前view 重写- hitTest withEvent:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { return nil;}
2.当前view不接收事件,但是,子 view 要接收,将事件传递给兄弟viewA(即:点击当前 view 空白的地方,让和他重叠的兄弟 view 接收事件):当前view 重写- hitTest withEvent:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { UIView *view = [super hitTest:point withEvent:event]; if(view == self){ return nil; } return view;}
3.设置 scrollView 的分页宽度。现在有这么一个需求:有一个 VC,上面有一个parentView,parentView 上面有个 scrollView,scrollView 上显示三张图片,滑动一下,就会滚出来一张图片,看清楚一张,就是说 scrollView 的分页是1/3VC.View。
思路:
设置scrollView的宽度为1/3VC.View。//这样分页宽度就是自己的宽度。
设置scrollView的 center 横向居中。
设置 scrollView.contentoffset = 1/3VC.View。//这样就显示了3张图片
开启分页模式:scrollView.pagingEnabled = YES。
设置scrollView.clipsToBounds = NO。//这样超出范围的视图也会显示。
然后重写scrollView所在的parentView的hitTest事件,让其返回值是UIScrollView对象。
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { return [self pointInside:point withEvent:event] ? scrollView : nil;}
- 关于hit-testing机制
- iOS事件分发机制(一) hit-Testing
- iOS事件分发机制(一) hit-Testing
- IOS消息机制之------Hit Testing 伪代码
- iOS Hit-Testing
- iOS hit-Testing
- iOS hit-Testing 2
- Hit-Testing in iOS
- Hit Testing Lines and Curves
- Win32 Series - Hit-Testing in Your Programs
- iOS Hit-Testing事件响应链
- iOS-hitTest:withEvent与自定义hit-testing规则
- 关于OWASP TESTING GUIDE
- 关于TestFlight Beta Testing
- 关于HIT的一点思考(1)
- Visual Layer Overview(5)Hit Testing in the Visual Layer
- IOS事件分发、Responder Chain(一)——hit-testing
- hit-Testing 子视图超出父试图部分上的控件响应事件
- ora-1017
- Struts1和Struts2的区别和对比
- 内存泄漏和溢出整理(二)
- HDU 5728 PowMod
- Libevent源码分析-----多线程、锁、条件变量(一)
- 关于hit-testing机制
- 第三章--不得不学的Fragment
- mysql性能优化-慢查询分析、优化索引和配置
- 冒泡排序
- test
- matlab作图如何改变坐标刻度
- ubuntu14.04+cuda-7.5(deb)+cuDNN+openCV+caffe 安装(安装笔记一)
- ios Cookies
- 手势识别