UISrollView是开发中最常见的控件,我们用它来展示各种界面,但是ScrollView的内部是怎么实现的呢,我写了一下代码研究了一下,大概原理是这样:
我们都知道每一个View都有一个CALayer,UIView的显示主要靠的是CALayer,每一个UIView在显示的时候都会对自己进行渲染,渲染的范围是根据bounds来确定的,但是当UIView被添加到父试图的时候需要确定位置,这时位置的确定是根据父视图的位置来确定的,即以父视图的原点来确定。如此我们看到的界面就显示出来了(即视图的光栅化和组合)。
视图在组合的时候应该在父视图上的位置
CompositedPosition.x = View.frame.origin.x - Superview.bounds.origin.x;
CompositedPosition.y = View.frame.origin.y - Superview.bounds.origin.y;
UIScrollView与普通的View最大的区别之处在于它是可以滑动的,并且内容不限于当前界面。此时我们如果把UIScrollView看成一个普通的View,那么其实这个View有一部分子视图是超出当前的视图界面的,此时就是一个不能滑动的ScrollView,那么如何让这个视图滑动呢?我们可以给这个视图添加一个移动手势,当我们移动的时候可以根据手势对ScrollView进行界面的改变,来展示那些超出屏幕的界面。如何操作呢,其实很简单,就是改变ScrollView的bounds,我们都知道子视图的位置的确定是根据父视图的原点来确定的,当我们改变父视图的原点之后,其实子视图的位置就改变了。此时我们再给改变父视图的原点加上动画就会出现类似滑动的效果。我们还可以根据手指移动的方向来确定视图滚动的方向。
contentOffset的最大值:
contentOffset.x = contentSize.width - bounds.size.width;
contentOffset.y = contentSize.height - bounds.size.height;
ScrollView有三个特别的属性,分别是contentSize、contentOffset和contentInsert,contentSize其实就是整个View的子视图的高度,由此来确定了整个view的滑动范围。 contentOffset其实就是每一次滑动的时候该变的原点的位置。我们可以自定义一个滑动的ScrollVIew,但是效果肯定没有系统的那么好了。至于contentInsert则是给scrollView添加一个额外的滚动区域。下面看一下它的具体使用:
当我们的手指开始触摸scrollview的时候,scrollview内部将会开始一个计时器,这个计时器判断以下情况:
(1)150ms内,触摸的手指没有任何动作,那么会把触摸的消息传递给subView去处理
(2)150ms内手指有明显的滑动,scrollView就会开始滚动,消息不会传递给子视图
(3)150ms内手指没有滑动,scrollview传递消息给子视图,但是之后手指开始滑动,scrollview传递touchesCancelled消息给子视图同时开始滚动。
scrollview有一个tracking属性,默认为YES,当150ms内手指发生了滑动,scrollView滑动,同时tracking属性变为NO,此时内部控件不会再响应触摸事件,当150ms内手指没有发生滑动,tracking属性继续保持为YES,内部控件可以响应触摸事件
scrollView还有一个属性delaysContentTouches,这个属性默认值为YES,如果设置为NO,那么无论手指滑动多快,触摸事件总会传递给内部控件。设置为NO可能会影响滑动性能。当为YES的时候,如果是在滑动那么内部控件不会响应触摸事件。