在之前看过一篇文章Android自定义控件之仿美团下拉刷新,就是实现仿美团下拉刷新。一直对ListView等控件的下拉刷新的了解程度,可能也就停留在用HeaderView来实现,然后重写onTouchEvent
,但是具体应该是怎样的呢?一直没有实际动手自己写过,于是抽空自己照着这篇博客自己写了一遍,以加深自己的理解。我对原博客进行摘录,重点写出一些对自己帮助大的内容。
刷新状态
一般下拉刷新应该都是会有三种状态:下拉刷新、松开刷新、正在刷新。
下拉刷新
实现思路:自定义View,通过设置进度值进行缩放。
用SeekBar来模仿一下下拉距离的进度。
自定义View代码:
1 | public class RefreshFirstView extends View { |
松开刷新
这里主要是一个帧动画。
1 |
|
正在刷新
与松开刷新一样,也是一个帧动画,这里便不做赘述。
三种状态通过自定义View,重写onMeasure来确保三个状态的View的宽高保持一致。
下拉刷新的实现
先贴一下原博客的代码:
1 | public class MeiTuanListView extends ListView implements AbsListView.OnScrollListener{ |
代码中已经有了很详细的注释了,看起来应该会比较轻松。
改进
写完之后运行,发现有2个地方可以改进。
下拉白块
在下拉刷新的时候,若下拉的高度很高,那么松开刷新后,再次下拉,会出现很大的一个空白块,影响视觉。
导致该问题的原因是在RELEASE_TO_REFRESH
状态下ACTION_UP
时,只是利用smoothScrollBy滑动到headerView的显示位置。但是此时,headerView的paddingTop属性依然是ACTION_MOVE
中设置的headerView.setPadding(0,(int)(-headerViewHeight+offsetY/RATIO) ,0, 0);
,其值跟offsetY有关,offsetY越大,那么paddingTop值就会越大,导致再次下拉会出现很大的空白块。
改进办法:利用Scroller滑动辅助类替换smoothScrollBy,在滑动的过程中不停设置headerView的paddingTop值。当滑动结束时,headerView的paddingTop正好等于0,即刚刚好显示。
刷新结束后立刻消失
刷新结束后,会直接设置headerView的paddingTop为-headerViewHeight,导致headerView立刻不可见,会显得比较突兀。
改进办法:依然是利用Scroller类滑动辅助类,通过滑动动画使headerView不可见。
改进后,我的代码是这样的:
1 | public class RefreshListView extends ListView implements ListView.OnScrollListener { |
讨论
在原博客中有这样的讨论:setOnRefreshComplete没必要暴露,隐藏在ListView里面更好。
个人觉得也确实是这样,我们使用下拉刷新只会关心onRefresh,对于setOnRefreshComplete是不关心的。
但是setOnRefreshComplete是必须要在onRefresh执行完之后才会执行,对于ListView它是不知道onRefresh在何时结束的,所以如果非要隐藏setOnRefreshComplete,我暂时没想到好的实现方案。
后面我找了一下下拉刷新相关的库,都有类似setOnRefreshComplete的方法。
XListView:
SwipeRefreshLayout:
希望有想法的大神不吝赐教~
感受
- 对于自己记忆中模棱两可的知识一定要自己动手做一遍,以加深印象。
- 可以通过缩放canvas,来实现自定义view的缩放。
- 通过设置paddingTop值来控制headerView的显示。
- 在查看XListView相关源码的时候,发现它是这样在View还没显示的时候获取高度的:
1
2
3
4
5
6
7
8mHeaderView.getViewTreeObserver().addOnGlobalLayoutListener(
new OnGlobalLayoutListener() {
public void onGlobalLayout() {
mHeaderViewHeight = mHeaderViewContent.getHeight();
getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
}); - onTouchEvent里的事件处理是非常繁杂的,当时自己写滑动删除的ListView时也重写过onTouchEvent,一定要细心。
我的代码
代码已上传至我的Github。