前言
前言: UIScrollView 和UITableView是iOS中最常用的控件。而UITableView又是继承自UIScrollView的,所以一个iOS程序员的工作可能会有很长一段时间是在折腾一个或多个UIScrollView。了解UIScrollView的属性和特点很有必要!
在我们通常的认知里,想要一个UIScrol lView随着我们的手指滑动而滑动,那么我们的手指必须在UIScrollView的范围内滑动并且这个scrollview上层没有任何别的view遮挡。但是其实我们是有办法改变这个范围的,使得即使我们在UIScrollView以外的地方滑动依旧可以使得UIScorllview产生滑动。
实现
如图我们在一个viewcontroller的view上添加了一个scrollview,然后又addsubview一个白色的topview遮挡scrollview,那么当我们尝试滑动scrollview的时候会发生以下情况:
原因是我们都知道了,根据iOS响应链的规则通过hit-test找到找到点击区域最上层的view,然后通过最上层的view找到firstResponder,让firstResponder处理这个事件。
响应链条在本次滑动事件的处理流程大致如下:当我们尝试在topview滑动的时候,会使用hit-test来找出最上层的view响应当前滑动事件。监测到白色topview是最上层的view所以会把事件交给白色topview,但是topview并没有不处理事件,所以需要向它nextResponder也就是它的superview,viewcontroller的view来处理,以此类推,发现并没有view能够处理这个事件,所以这个事件被作废。我们的scrollview全程并未参与自然无法接受事件
关于响应链的详细原理这里并不展开。
转机
点开UIScrollView.h,我们能看到UIScrollView有一个属性panGestureRecognizer:
@property(nonatomic, readonly) UIPanGestureRecognizer *panGestureRecognizer API_AVAILABLE(ios(5.0));
打印该属性如下:
(lldb) po self.scrollView.panGestureRecognizer
<UIScrollViewPanGestureRecognizer: 0x7fb24a7080a0; state = Possible; delaysTouchesEnded = NO; view = <UIScrollView 0x7fb24c01b200>; target= <(action=handlePan:, target=<UIScrollView 0x7fb24c01b200>)>>
发现这个手势是一个UIScrollViewPanGestureRecognizer,也就是处理UIScrollView滑动的手势,它的view是
view = <UIScrollView 0x7fb24c01b200>;
也就是UIScrollView本身。这也就是为什么UIScrollView的滑动一定要在UIScrollView范围内。
既然UIScrollView把处理滑动的手势暴露给我们了,那我们是不是可以把这个手势添加到别的view上呢?
答案是:可以!
正如我们刚才说的响应链的原理,我们只要把UIScrollView的panGestureRecognizer添加到topview和scrollview的共同父view,也就是这里的UIViewController的view上就可以实现点击整个屏幕都能滑动UIScrollView了!
[self.view addGestureRecognizer:self.scrollView.panGestureRecognizer];
再看一下效果:
更加惊喜的是,我们不仅可以修改UIScrollView的手势触发view为任意view,而且可以得到这个手势的回调:
[self.scrollView.panGestureRecognizer addTarget:self action:@selector(scrollViewPan:)];
- (void)scrollViewPan:(UIPanGestureRecognizer*)gesture
{
if (gesture.state == UIGestureRecognizerStateBegan) {
}else if (gesture.state == UIGestureRecognizerStateEnded || gesture.state ==
}else if (UIGestureRecognizerStateChanged) {
}
}
不用担心这个回调会影响scrollview本身的滑动,他们并不会冲突。
拓展
由此拓展开来,我们可以把 scrollview的panGerturerecognizer属性添加到任意我们想要添加的view上,实现更加有趣的效果,比如:
结论:改变UIScrollView的滑动手势panGerturerecognizer的作用view,就可以改变UIScrollView的滑动手势响应view,实现在任意view上响应UIScrollView的滑动手势