UIScrollView的一些特点
是个麻烦的控件,这里先问几个问题:
1. 如果我触摸一下屏幕,哪个view会最先收到触摸消息呢(touchesBegan)?
答案是,如果所有view都是UIView的话,那么最外层的子view会先收到该消息。这个机制就是通过 UIView中的hitTest:withEvent: 实现的。这个函数的逻辑是这样的(官方文档):
This method traverses the view hierarchy by sending the pointInside:withEvent: message to each subview to determine which subview should receive a touch event. If pointInside:withEvent: returns YES, then the subview’s hierarchy is traversed; otherwise, its branch of the view hierarchy is ignored. You rarely need to call this method yourself, but you might override it to hide touch events from subviews.
也就是说底层的父view的hitTest函数先被调用,在这里遍历调用subView的hitTest,直到找到最外层的subView,然后返回该view,系统再把touch事件传给这个view。
2. tableView的cell我点击一下,打开一个新页面,但如果飞快的swipe一下,tableView会是上下滚动,而cell即不会highlight,也不会打开新页面,这是如何实现的呢?
tableView继承自UIScrollView,这个功能实际上是UIScrollView来实现的。它是如何做的呢?根据问题一,UIView的默认行为是将touch事件传递给最外层的subView。实际上UIScrollView重载了hitTest:withEvent:,他永远只返回自己。
这里把UIScrollView的几个要点总结下:
从你的手指touch屏幕开始,scrollView开始一个timer,如果:
1. 150ms内如果你的手指没有任何动作,消息就会传给subView。
2. 150ms内手指有明显的滑动(一个swipe动作),scrollView就会滚动,消息不会传给subView,这里就是产生问题二的原因。
3. 150ms内手指没有滑动,scrollView将消息传给subView,但是之后手指开始滑动,scrollView传送touchesCancelled消息给subView,然后开始滚动。
观察下tableView的情况,你先按住一个cell,cell开始高亮,手不要放开,开始滑动,tableView开始滚动,高亮取消。
delaysContentTouches的作用:
这个标志默认是YES,使用上面的150ms的timer,如果设置为NO,touch事件立即传递给subView,不会有150ms的等待。
cancelsTouches的作用:
这个标准默认为YES,如果设置为NO,这消息一旦传递给subView,这scroll事件不会再发生。