Android      android极简ListView下拉刷新上滑加载   
文章目录  [隐藏]

通过搜索引擎找到的ListView下拉刷新上滑加载示例几乎都用到了OnScrollListener,同时篇幅较大,新手理解不是很容易。本文所示为初学时笔记内容,比较浅显,相信入门可用。

1.最基本构思

本示例讲解个人的简单构思。

下拉刷新

  • 下拉的首要条件是ListView内 顶部已经没有更多的Item了。此时有手指下拉(从上而下滑动)动作我们就可以刷新适配器。

  • 通常的设计是,给ListView添加一个header。header默认隐藏,隐藏的方式一般是设定其相对于LV的padding值,padding top为负的自身高度。这样,当我们看起来正文item的第一条是最顶部条目时,其实还有header在屏幕外。
  • 手指按下向下滑动,本来应该是没有任何反应的。手指滑动中新的位置和按下位置的距离越来越大,我们让header的padding和这个不断更新的距离关联;手指越向下滑,padding值越来越大,header就越移动到ListView内部。
  • 当手指的移动距离或header的padding值达到一定数额,我们就让它固定,执行刷新。

上滑加载

  • 上滑加载要多考虑一个情况,就是当前可见的item中没有最底部的条目。如果是这样就让ListView按默认滚动。之所以说“多考虑”是因为ListView第一次运行加载数据结束总是最顶端显示第一条item。

  • 如果可见的最底一条是最后一个item了(当然不会是footer,因为默认其padding为负的自身高度),那么根据情况执行上滑。
  • 手指上滑产生的距离是负数,而且越向上滑,值越小。将footer的padding值与之关联,距离越小,padding越大,footer则越上移。
  • 当footer的padding值增大到一定数额,固定,显示footer内的动画或干点别的,并执行加载。



2.自定义ListView

以上构思希望都在ListView自身内完成。

下拉刷新

  • 首先是得到当前可见的最顶条目的索引,如果是0,当前就有了下拉刷新的条件,否则就是一般的向下滚动而已。

  • 搜索到的获取最顶可见条目索引的方法基本都是通过OnScrollListeneronScrll方法,本示例没有这样。很简单,直接使用ListView自身的 getFirstVisiblePosition() 方法即可。
  • 如果getFirstVisiblePosition()得到的不是0,那么return super.onTouchEvent(ev)按照一般滑动操作;如果得到的是0,那么就应该让header的padding做出响应。mHeaderView.setPadding(0, (int) (distanceY - measuredHeaderHeight), 0, 0);,distanceY即手指滑动距离,measuredHeaderHeight即header的自身高度。

上拉加载

  • 对应的,getLastVisiblePosition()可以得到当前可见的最底一个item的索引,同时配合getAdapter().getCount()得到全部item的数量,这个数量-1就是最后一个item的索引。当这两个索引相同,就具备了上拉加载的条件。否则就按照一般滚动执行。


3.自定义ListView代码

注意header和footer也算是item,当添加了这两项之后,LV滚动到最顶getFirstVisiblePosition()得到的0索引实际是header的索引;LV滚动到最底,getLastVisiblePosition()得到的实际是footer的索引。footer索引等于item总数减1。它们的索引和因padding值导致的隐藏或显示无关。实际就算对它们setVisible(View.GONE或INVISIBLE)也不影响。
下面是最基本的下拉刷新和上滑加载代码,其中仍然有一些细节需要注意:

这只是很简陋的实现了功能,复位动画等还待完善。

4.数据更新流程和状态动画

当拿起手指,满足了执行更新的距离就可以执行刷新或加载了。此时的数据请求一般在Activity中执行,而当前我们还处于ListView中,所以要和Aty打个招呼。
如何打招呼有很多方法:Handler、Messenger、Broadcast、静态变量轮询、文件内容轮询,还有最常用的接口回调。

通过接口回调请求数据

  • 本例在ListView内部定于一个public属性的接口IUpdateOrLoadBack(通常是一个独立的java文件),其中是回调方法updateOrLoadBack(int flag),flag用以区分下拉还是上滑以调研不同的服务器地址。

  • 在ListView中声明一个IUpdateOrLoadBack类型的全局变量,并提供一个public方法,用来初始化这个变量setUpdateOrLoadBack(IUpdateOrLoadBack updateOrLoadBack){ this.updateOrLoadBack = updateOrLoadBack; }
  • 这样Aty中得到ListView的实例后就可以定义LV的回调变量了mListView.setUpdateOrLoadBack(new IUpdateOrLoadBack() {...这里进行数据请求},这里的“new IUpdateOrLoadBack() {...}”就成为了Aty中的一个匿名实例,属于主UI线程。并且传入ListView作为其成员。
  • 终于,当下拉或上滑手指拿起后,ListView就可以在onTouch事件的ACTION_UP时调用Aty传入的回调器updateOrLoadBack.updateOrLoadBack(0);通知主UI进行数据请求了。
  • 再者,Aty请求数据过程中,一般都显示一个动画表示命令正在执行;请求结束,重置一下header和footer的位置。

数据请求时的动画

安卓中的动画类型有多种:逐帧动画{AnimationDrawable}、补间动画{[xml方式{alpha、rotate、scale、set、translate}],[java代码方式{AnimationSet-组合动画、AlphaAnimation、RotateAnimation、ScaleAnimation、TranslateAnimation、ObjectAnimator-属性动画}]},等等。逐帧动画一般用于控件自身,补间动画多用于场景切换。现在我们用的就是AnimationDrawable。

  • 首先读取本地图片Drawable d = getContext().getResources().getDrawable(R.drawable.pic);,然后定义一个AD实例animHeader = new AnimationDrawable();,再向动画实例添加图片animHeader.addFrame(d, 100);,100为毫秒数。这里可以不断添加不同的图片。最后可以可以设置循环播放animHeader.setOneShot(false);

  • 一个ad实例只能用于一个View控件。首先得到用于显示动画的ImageView控件,然后指定其ImageDrawable属性mHeaderAnim = (ImageView) mHeaderView.findViewById(R.id.iv_header_anim);
    mHeaderAnim.setImageDrawable(animHeader);
  • 当手指拿起的时候,启动动画animHeader.start();,当前还有对应的停止方法可以使用animHeader.stop();

更新后的代码

Aty

ListView



[download id="1707"]

承接App定制、企业web站点、办公系统软件 设计开发,外包项目,毕设