这篇我们来讲如何将loading圆圈动画和TableView结合起来一起使用。

首先,我们需要将loading圆圈和提示label加到一个view上去显示,实现的主要点有两点:第一,在上拉或者下拉的过程中,我们通过progress值去控制loading圆圈的动画和label的alpha值,第二,通过设置拉动的方向来设置label提示的内容

然后,我们该怎么去获得这个progress值呢?

首先,我们在初始化的时候需要监听所关联的scrollView的contentOffset值,

1
[self.scrollView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];

然后在observeValueForKeyPath里面,我们获取contentOffset的最新值,

1
CGPoint contentOffset = [[change valueForKey:NSKeyValueChangeNewKey] CGPointValue];

然后再通过计算来改变progress值,

1
self.progress = MAX(0.0, MIN(fabs((self.originOffset + contentOffset.y)/kMaxPullDownDistance), 1.0));

(注:在这里有个originOffset值,这个是我用来处理是否有导航栏的情况,有则该值为64.0,没有则为0.0)

计算的思路是我们通过所关联的scrollView的contentOffset与我们所设置的最大的拉动距离值相除作比较,得到的就是拉动的一个范围比例,因为contentOffset会超出我们设置的最大拉动距离,所以我们需要再取最小最大值,来获取到最后的progress值。


在这里插一个小的知识点,因为这个是在写上拉时,所必须知道的一个点,contentOffset是怎么算的?

contentOffset是scrollview当前显示区域顶点相对于frame顶点的偏移量

但当上拉刷新之后,此时scrollview的contentSize变化了,(contentSize指的是可显示区域),在计算contentOffset时,需要将contentSize减去scrollView的高度,来和contentOffset作比较。

拿到progress之后,此时我们离完成这个控件的任务就差不多了。

首先,我们需要将progress赋值给loading圆圈和提示label,

然后如果我们拉动的距离超过了设置最大值的时候,我们做loading,并且通过block让外部做一些网络请求或者其他的操作

1
2
3
4
5
6
7
8
9
10
[self startLoading:self.refreshView];

// 0.3s animation time is the best experience
[UIView animateWithDuration:0.3 animations:^{
self.scrollView.contentInset = UIEdgeInsetsMake(kMaxPullDownDistance + self.originOffset, 0, 0, 0);
} completion:^(BOOL finished) {
if (self.refreshingBlock) {
self.refreshingBlock();
}
}];

在上拉时,有一点不同,scrollView的contentSize可能是会变化的,而我们的控件是要始终显示在它的最下方的,所以我们在上拉时,需要对contentSize也加监听

1
[self.scrollView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];

并且在observeValueForKeyPath里面,需要设置控件的center来改变我们的显示位置,以及progress值,其他操作都和下拉刷新一样。

ok,我们的上拉下拉刷新控件完成喽~