UIScrollView滚动停止监测

今天在做一个控件的动画,动画需求是这样的,当UICollectionView滚动开始和滚动结束的时候,一个底部控件需要做淡出淡入的效果。

在iOS中使用UIScrollView的子类的时候,需要知道UIScrollView滚动动画是否结束,一般我们都是通过UIScrollViewDelegate中去寻找方法。

1
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView

第一眼就相中它了,在我使用的过程中发现,在拖拽UIScrollView之后动画停止的时候,这个函数根本不会触发。翻看了apple给出的文档

The scroll view calls this method at the end of its implementations of 
the setContentOffset:animated: and scrollRectToVisible:animated: 
methods, but only if animations are requested.

文档中说明该函数只作用于 setContentOffset:animated: 和 scrollRectToVisible:animated: 这两个函数,调用时机是动画结束之后,并且只有当animated为YES的时候。后来查了一些资料发现还有一些函数也是会被调用的。归纳有以下几个

// UIScrollView的setContentOffset:animated: 
// UIScrollView的scrollRectToVisible:animated:
// UITableView的scrollToRowAtIndexPath:atScrollPosition:animated:
// UITableView的selectRowAtIndexPath:animated:scrollPosition:

接下来我又找了下面这个函数,看上去挺像我们要找的

1
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView

从实验来看,可以到达效果,但是有个bug出现了,这个函数有点不靠谱,不是一个自然停止会调用的,在手势中断动画滚动的时候也会调用。

之后在stackoverFlow上面找到了答案How to detect when a UIScrollView has finished scrolling

1
2
3
4
5
6
7
8
9
10
-(void)scrollViewDidScroll:(UIScrollView *)sender
{
[NSObject cancelPreviousPerformRequestsWithTarget:self];
[self performSelector:@selector(scrollViewDidEndScrollingAnimation:) withObject:nil afterDelay:0.1];
}

-(void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
{
[NSObject cancelPreviousPerformRequestsWithTarget:self];
}

上面的方法用的相当巧妙,至于原理就不解释了。