ListView和AsyncTask结合实现下拉刷新
2015-03-28 22:58
183 查看
无疑,在Android开发中,ListView是使用非常频繁的控件之一,ListView提供一个列表的容易,允许我们以列表的形式将数据展示到界面上,但是Google给我们提供的原生ListView的控件,虽然在功能上很强大,但是在用户体验和动态效果上,还是比较差劲的。为了改善用户体验,市面上纷纷出现了各种各样的自定义的ListView,他们功能强大,界面美观,使我们该需要学习的地方。其中,使用最频繁的功能无疑就是ListView的下拉刷新和上拉加载数据了,几乎在每一款内容型的App中都可以找到这种控件的身影,尤其是需要联网获取数据的模块,使用的就更为频繁了,so,我们很有必要了解下这种效果是怎么实现的。
说白了实现ListView的下拉刷新和上拉加载数据的功能无非是对ListView实现加header和加footer,在适当的时候分别显示header和footer,然后又在适当的时候隐藏header和footer。主要是根据ListView的setPadding、addHeaderView和addFooterView等方法来实现。AsyncTask,是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程.
下面就ListView和AsyncTask如何实现数据加载和下拉刷新和上拉加载数据的具体代码,代码注释很详细:
源码下载源码下载
自定义MyListView
:
![](http://img.blog.csdn.net/20150328232158944?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2FuaXUxMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
说白了实现ListView的下拉刷新和上拉加载数据的功能无非是对ListView实现加header和加footer,在适当的时候分别显示header和footer,然后又在适当的时候隐藏header和footer。主要是根据ListView的setPadding、addHeaderView和addFooterView等方法来实现。AsyncTask,是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程.
下面就ListView和AsyncTask如何实现数据加载和下拉刷新和上拉加载数据的具体代码,代码注释很详细:
源码下载源码下载
自定义MyListView
:
package cn.zxw.pull.refresh.view; import java.text.SimpleDateFormat; import java.util.logging.SimpleFormatter; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.animation.Animation; import android.view.animation.RotateAnimation; import android.widget.AbsListView; import android.widget.AbsListView.OnScrollListener; import android.widget.ImageView; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; import cn.zxw.pull.refresh.R; public class MyListView extends ListView implements OnScrollListener { // 加载数据的接口 public interface OnListViewLoadDataListener { public void onLoadNewData(); // 加载更多数据 public void onLoadMoreData(); } private OnListViewLoadDataListener onListViewLoadDataListener; public void setOnListViewLoadDataListener( OnListViewLoadDataListener onListViewLoadDataListener) { this.onListViewLoadDataListener = onListViewLoadDataListener; } private static final String TAG = "MyListView"; private View header; private ImageView iv_arrow; private ProgressBar pb; private TextView tv_state; private TextView tv_time; private int height; enum HeaderState { PULL_DOWN_REFRESH, // 下拉刷新 RELEASE_REFRESH, // 释放刷新 REFRESHING// 正在刷新 } // 设置默认状态 private HeaderState state = HeaderState.PULL_DOWN_REFRESH; // ListView头文字的信息 private String[] stateInfos = new String[] { "下拉刷新", "释放刷新", "正在刷新" }; public MyListView(Context context) { super(context); } public MyListView(Context context, AttributeSet attrs) { super(context, attrs); initHead(); initFooter(); setOnScrollListener(this); } /** * 初始化footer */ private void initFooter() { footer = View.inflate(getContext(), R.layout.footer, null); footer.measure(0, 0); footerHeight = footer.getMeasuredHeight(); footer.setPadding(0, -footerHeight, 0, 0); addFooterView(footer); } /** * 初始化listview的头部 */ private void initHead() { header = View.inflate(getContext(), R.layout.header, null); iv_arrow = (ImageView) header.findViewById(R.id.iv_arrow); pb = (ProgressBar) header.findViewById(R.id.pb); tv_state = (TextView) header.findViewById(R.id.tv_state); tv_time = (TextView) header.findViewById(R.id.tv_time); pb.setVisibility(View.INVISIBLE);// 隐藏pb addHeaderView(header);// 添加header,然后要隐藏header //int height = header.getHeight(); 如果一个控件没有显示 是无法获取宽高 layout header.measure(0, 0);//Android中控件的位置必须先测量 height = header.getMeasuredHeight();//获取控件的高度 header.setPadding(0, -height, 0, 0);// 隐藏控件,即是将控件设置在屏幕顶部之外 } public MyListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } private boolean isLoadingData = false;// 是否加载更多数据 // 滑动状态改变 // 闲置和飞行状态 listview必须是已经显示到最后下处理 @Override public void onScrollStateChanged(AbsListView view, int scrollState) { int lastVisiblePosition = getLastVisiblePosition();// 获取listview最后显示的下标 int count = getAdapter().getCount(); // 闲置状态和飞行状态 还必须是ListView已经显示到最后 没有在加载数据 if ((scrollState == OnScrollListener.SCROLL_STATE_IDLE || scrollState == OnScrollListener.SCROLL_STATE_FLING) && lastVisiblePosition == count - 1 && !isLoadingData) { isLoadingData = true; footer.setPadding(0, 0, 0, 0); // 脚其实还是没有显示 setSelection(count); if (onListViewLoadDataListener != null) { onListViewLoadDataListener.onLoadMoreData(); } } switch (scrollState) { case OnScrollListener.SCROLL_STATE_IDLE:// 闲置 break; case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:// 滑动 break; case OnScrollListener.SCROLL_STATE_FLING:// 飞行 break; default: break; } } /** * firstVisibleItem 屏幕上显示的第一个条目的下标 *visibleItemCount 屏幕上显示的条目总数 * totalItemCount 条目总数 */ private int firstVisibleItem;// 记录第一个条目位置 @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { this.firstVisibleItem = firstVisibleItem; Log.i(TAG, "firstVisibleItem:" + firstVisibleItem); } private int startY; private int footerHeight; private View footer; // 滑动改变header @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: Log.i(TAG, "ACTION_DOWN"); startY = (int) ev.getY(); break; case MotionEvent.ACTION_MOVE: Log.i(TAG, "ACTION_MOVE"); // 显示的是第一个条目 if (firstVisibleItem == 0 && state != HeaderState.REFRESHING) { int moveY = (int) ev.getY(); int disY = moveY - startY; // 控制header的显示 int top = -height + disY; if (top > 0 && state == HeaderState.PULL_DOWN_REFRESH) {// 原来是下拉刷新 // 现在置为释放刷新 state = HeaderState.RELEASE_REFRESH; RotateAnimation animation = getRotateAnimation1(); iv_arrow.setAnimation(animation); tv_state.setText(stateInfos[1]); } else if (top <= 0 && state == HeaderState.RELEASE_REFRESH) { // 原来是释放刷新 现在变为下拉刷新 state = HeaderState.PULL_DOWN_REFRESH; RotateAnimation animation = getRotateAnimation2(); iv_arrow.setAnimation(animation); tv_state.setText(stateInfos[2]); } header.setPadding(0, top, 0, 0); } break; case MotionEvent.ACTION_UP: Log.i(TAG, "ACTION_UP"); // 用户松开手指:1 下拉刷新 2 释放刷新 if (state == HeaderState.PULL_DOWN_REFRESH) { // 把头直接隐藏 header.setPadding(0, -height, 0, 0); } else if (state == HeaderState.RELEASE_REFRESH) { // 把头显示在第一行 作为一个正常的显示 // 把头的状态进行改变 header.setPadding(0, 0, 0, 0); state = HeaderState.REFRESHING; iv_arrow.clearAnimation();// 清除动画 iv_arrow.setVisibility(View.INVISIBLE); // 箭头无法隐藏:iv_arrow有动画 pb.setVisibility(View.VISIBLE); tv_state.setText(stateInfos[2]); // 通知activity加载数据 if (onListViewLoadDataListener != null) { onListViewLoadDataListener.onLoadNewData(); } } break; default: break; } return super.onTouchEvent(ev); } public RotateAnimation getRotateAnimation1() { RotateAnimation rotateAnimation = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); rotateAnimation.setDuration(200); rotateAnimation.setFillAfter(true); return rotateAnimation; } public RotateAnimation getRotateAnimation2() { RotateAnimation rotateAnimation = new RotateAnimation(-180, -360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); rotateAnimation.setDuration(200); rotateAnimation.setFillAfter(true); return rotateAnimation; } // 隐藏头 // 1.状态改为下拉刷新 // 2.隐藏进度条 显示箭头 修改文字 // 3.刷新的事件 // 4.header设置padding public void hideHeader() { state = HeaderState.PULL_DOWN_REFRESH; pb.setVisibility(View.INVISIBLE); iv_arrow.setVisibility(View.VISIBLE); tv_state.setText(stateInfos[0]); long mills = System.currentTimeMillis(); SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); String dateStr = format.format(mills); tv_time.setText("上次刷新的时间为:" + dateStr); header.setPadding(0, -height, 0, 0); } // 隐藏footer public void hideFooter() { footer.setPadding(0, -footerHeight, 0, 0); isLoadingData = false; } }MainActivity:
package cn.zxw.pull.refresh; import java.util.ArrayList; import java.util.List; import cn.zxw.pull.refresh.view.MyListView; import cn.zxw.pull.refresh.view.MyListView.OnListViewLoadDataListener; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.SystemClock; import android.app.Activity; import android.widget.ArrayAdapter; public class MainActivity extends Activity implements OnListViewLoadDataListener { protected static final int SUCCESS_LOAD_NEW_DATA = 0; protected static final int SUCCESS_LOAD_MORE_DATA =1; private MyListView lv; private ArrayAdapter<String> adapter; private List<String> objects; Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { switch (msg.what) { case SUCCESS_LOAD_NEW_DATA: String data = (String) msg.obj; objects.add(0,data); adapter.notifyDataSetChanged(); lv.hideHeader(); break; case SUCCESS_LOAD_MORE_DATA: List<String> list = (List<String>) msg.obj; objects.addAll(list); adapter.notifyDataSetChanged(); lv.hideFooter(); break; default: break; } }; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); lv = (MyListView) findViewById(R.id.lv); // 值的初始化 objects = new ArrayList<String>(); for (int i = 0; i < 13; i++) { objects.add("初始化的数据" + i); } adapter = new ArrayAdapter<String>(getApplication(), android.R.layout.simple_list_item_1, android.R.id.text1, objects); lv.setAdapter(adapter); lv.setOnListViewLoadDataListener(this); } @Override public void onLoadNewData() { new Thread() { public void run() { SystemClock.sleep(3000); String data = "加载的数据"; Message msg = Message.obtain(); msg.what = SUCCESS_LOAD_NEW_DATA; msg.obj = data; handler.sendMessage(msg); }; }.start(); } @Override public void onLoadMoreData() { new MyAsyncTask().execute(""); } //Params 参数:一般都是要执行下载的路径 String Progress 进度条的值 Integer, Result 结果 Bitmap String List<String> private class MyAsyncTask extends AsyncTask<String , Integer, List<String>>{ //准备 @Override protected void onPreExecute() { super.onPreExecute(); } //执行后台的耗时操作 @Override protected List<String> doInBackground(String... params) { SystemClock.sleep(3000); List<String> list=new ArrayList<String>(); for (int i = 0; i <5; i++) { list.add("加载更多数据"+i); } return list; } //下载完成后 @Override protected void onPostExecute(List<String> result) { super.onPostExecute(result); objects.addAll(result); adapter.notifyDataSetChanged(); lv.hideFooter(); } //必须是有另外一个方法的调用才会调用该方法 //publishProgress() 该方法一般都是在doInBackground(String... params)里面调用 @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); } } }如果想详细知道AsyncTask可以参考scott's的博客
相关文章推荐
- 谈谈关于编程的良好习惯以及结合ListView和AsyncTask实现异步下载歌曲 推荐
- android SwipeRefreshLayout与ListView结合实现下拉刷新,加载功能
- Android中ListView下拉刷新的实现
- React-Native|实现ListView下拉刷新加载更多
- 自定义ListView实现下拉刷新
- 【处女作】android中的ListView结合BaseAdapter实例 ,加入ViewHolder实现高性能ListView
- Android自定义ListView实现下拉刷新,效果仿SwipeRefreshLayout
- 自定义ListView,如何实现下拉刷新
- Android中ListView下拉刷新的实现
- Android自定义ListView,轻松实现上下拉刷新,一看就懂,一学就会,超简单。
- Android UI--自定义ListView(实现下拉刷新+加载更多)
- android开发游记:listview下拉刷新和上拉加载的实现
- 教你自定义ListView实现下拉刷新,上拉加载更多
- Android实现上拉加载更多以及下拉刷新功能(ListView)
- 重写ListView实现下拉刷新上拉加载
- 手把手教你轻松实现listview下拉刷新
- 利用第三方开源框架 PullToRefreshListView 实现下拉刷新
- Android学习笔记:ListView上拉加载,下拉刷新的实现
- Android SwipeActionAdapter结合Pinnedheaderlistview实现复杂列表的左右滑动操作
- ListView (4)滚动事件/上拉刷新/下拉刷新的实现