问题:
如果在UIScrollView的上面放置了一个按钮,那么这个按钮点击的时候,按钮的高亮状态的图片是不能显示的。
原因:
这个由于UIScrollView和UIButton两者的事件响应的冲突引起的。
解决方案:
这时候需要在UIScrollView的身上动手了,自定义一个CustomScrollView,重写里面的touchesShouldCancelInContentView方法,然后用自定义的这个CustomScrollView,实例化后,设置其delaysContentTouches的值为false,这样就解决了。
代码:
class CustomScrollView:UIScrollView{
override func touchesShouldCancelInContentView(view: UIView) -> Bool {
return true
}
}
let scrollVeiw = CustomScrollView()
scrollVeiw.delaysContentTouches = false
原因进一步分析:
- 1:因为scrollView有一个150ms的延时判断,当我们的手指放在scrollView上时,如果在这150ms内我们的手指有移动,那么这是事件就会判断为“拖动scrollView的事件”,就不会被传递给它的子控件了;如果在这150ms内手指没有移动,则将这个touch事件传递给其最适合响应的子控件。那么显然将这个延时判断去除问题就显然解决了(self.scrollVeiw.delaysContentTouches = false)。
- 2:但是又会产生新的问题,就是当我们手指落在Button上时开始滑动scrollView,这时scrollView就不会滑动了。解决方案就是重写scrollView的touchesShouldCancelInContentView方法,返回false。当UIScrollView将touch事件交给子view后,当手指发生滑动时,调用此方法,假如返回false,则将touch事件交给子view,如果返回false,则交给UIScrollView处理,产生滑动。
UIScrollView的工作原理:
UIScrollView的工作原理,当手指touch的时候,UIScrollView会拦截Event,会等待一段时间,在这段时间内,如果没有手指没有移动,当时间结束时,UIScrollView会发送tracking events到子视图上。在时间结束前,手指发生了移动,那么UIScrollView就会进行移动,从而取消发送tracking。
用户touch —> tracking真 —> 如果点击一个可交互视图上,判断逻辑过程如下:
步骤1:根据delaysContentTouches的值,判断什么时候步骤2(立刻还是判断一定条件);
步骤2:调用touchesShouldBegin方法,如果返回值为yes,touch事件传给子视图;如果为no,touch事件不传给子视图,进入状态n。(跳转)
步骤3:touch move的,
3.1 如果canCancelContentTouches为no,不调用touchesShouldCancelInContentView方法,类也不scroll,进入状态m;
3.2 如果canCancelContentTouches为yes,调 用touchesShouldCancelInContentView,根据touchesShouldCancelInContentView方法的返回值;如果是yes,进入状态s。如果是no,进入状态m。
状态n :tracking为真,如果touch move的就scroll,touch松开,进入状态e
状态s :touch move中,类scroll,如果touch松开,进入状态e
状态m:touch move中,类不scroll,如果touch松开,进入状态e
状态e : 结束