1.我们需要考虑的listview当前处于的几种状态
1)默认状态(DONE=3) 表示加载完成,刷新头部消失不见
2)正在刷新的状态(REFRESHING=2) 表示正在刷新的状态值
3)刚开始下拉但是还没有变成释放刷新的地方(PULL_To_REFRESH=1) 表示将要进行刷新
4)松开手就可以刷新的状态(RELEASE_To_REFRESH=0) 表示松开手就开始进行刷新
2.我们需要考虑listview下拉刷新时需要考虑的几个动作。
如何判断这些动作的产生?
我们可以实现ontouchevent的事件接口
1.当手指第一次触摸屏幕时,通过MotionEvent.ACTIOIN_DOWN记录下这个点击的Y轴坐标(startY)。
2.当手指移动的时候,通过MotionEvent.ACTION_MOVE做出相应的动作
这个比较复杂一点,首先你需要判断当前listview处于上面状态中的哪一个状态
1)如果处于DONE的状态,并且当前所在的位置(tempY>startY),改变当前的state状态
2)如果处于PULL_To_REFRESH状态,判断当前手指移动的距离的三分之一是不是大于头部的宽度,如果是则将当前的state改变成RELEASE_To_REFRESH,如果tempY<=startY,则将当前的状态改变成DONE。
3)如果当前处于RELEASE_To_REFRESH状态,判断当前手指移动的距离的三分之一是不是小于头部的宽度,如果是state变成PULL_To_REFRESH,如果tempY小于等于startY,则将state变成DONE.
4)如果当前处于REFRESHING状态,则不做任何处理。
3.上面的两种事情解决了,我们就需要根据手指移动的距离动态显示头部刷新框显示的大小
还需要根据state状态改变头部刷新框的显示内容
4.还需要注意的一点就是监听listview的onScroll函数,假如当前listview的firstVisibleItem等于0,才可以进行下拉刷新的动作。
PullRefreshListview的文件内容
package com.example.pullrefreshlistview;import java.util.Date;import java.util.zip.Inflater;import javax.crypto.spec.IvParameterSpec;import android.content.Context;import android.provider.SyncStateContract.Constants;import android.util.AttributeSet;import android.util.Log;import android.view.LayoutInflater;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.view.animation.LinearInterpolator;import android.view.animation.RotateAnimation;import android.widget.AbsListView;import android.widget.ImageView;import android.widget.LinearLayout;import android.widget.ListAdapter;import android.widget.ListView;import android.widget.AbsListView.OnScrollListener;import android.widget.ProgressBar;import android.widget.TextView;public class PullRefreshListview extends ListView implements OnScrollListener {LayoutInflater inflater;/** 设置布局变量参数*/int headerContentHeight;// 上拉显示框的宽度int state; // 当前状态final int REFRESHING = 2; // 正在刷新的状态值final int DONE = 3; // 表示加载完成int RATIO = 3;public final int RELEASE_To_REFRESH = 0; // 松开手刷新:准备从pull_to_refresh到refreshing,假如手机又上移会变成从新变成DONEpublic final int PULL_To_REFRESH = 1; // 从下拉返回到不刷新的状态值int startY; // 记录一下上一次记录的y坐标boolean isBack;boolean isRecored;OnRefreshListener listener; // 设置刷新的接口boolean isRefreshable = true; // 当前是够能够刷新private RotateAnimation animation;private RotateAnimation reverseAnimation;public void setListener(OnRefreshListener listener) {this.listener = listener;}/** Listview头部下拉刷新的布局*/private LinearLayout headerView;private TextView lvHeaderTipsTv;private TextView lvHeaderLastUpdatedTv;private ImageView lvHeaderArrowlv;private ProgressBar lvHeaderProgressBar;/** 定义头部下拉刷新的布局高度+++*/public PullRefreshListview(Context context, AttributeSet attrs) {super(context, attrs);init(context);}private void init(Context context) {setCacheColorHint(getResources().getColor(R.color.transparent));inflater = LayoutInflater.from(context);headerView = (LinearLayout) inflater.inflate(R.layout.lv_header, null);lvHeaderTipsTv = (TextView) headerView.findViewById(R.id.lvHeaderTipsTv);lvHeaderLastUpdatedTv = (TextView) headerView.findViewById(R.id.lvHeaderLastUpdatedTv);lvHeaderArrowlv = (ImageView) headerView.findViewById(R.id.ivHeaderArrowlv);lvHeaderArrowlv.setMinimumHeight(70);lvHeaderArrowlv.setMinimumWidth(50);lvHeaderProgressBar = (ProgressBar) headerView.findViewById(R.id.ivHeaderProgressBar);measureView(headerView);headerContentHeight = headerView.getMeasuredHeight();Log.i("headerContentHeight", headerContentHeight+"");headerView.setPadding(0, -1 * headerContentHeight, 0, 0);headerView.invalidate();addHeaderView(headerView);animation = new RotateAnimation(0, -180,RotateAnimation.RELATIVE_TO_SELF, 0.5f,RotateAnimation.RELATIVE_TO_SELF, 0.5f);animation.setInterpolator(new LinearInterpolator());animation.setDuration(250);animation.setFillAfter(true);reverseAnimation = new RotateAnimation(-180, 0,RotateAnimation.RELATIVE_TO_SELF, 0.5f,RotateAnimation.RELATIVE_TO_SELF, 0.5f);reverseAnimation.setInterpolator(new LinearInterpolator());reverseAnimation.setDuration(250);reverseAnimation.setFillAfter(true);setOnScrollListener(this);state = DONE;isRefreshable = false;}/*** * @param child* 该函数用来估计child的width和height*/private void measureView(View child) {ViewGroup.LayoutParams params = child.getLayoutParams();if (params == null) {params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT);}int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0, params.width);int lpHeight = params.height;int childHeightSpec;if (lpHeight > 0) {childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,MeasureSpec.EXACTLY);} else {childHeightSpec = MeasureSpec.makeMeasureSpec(0,MeasureSpec.UNSPECIFIED);}child.measure(childWidthSpec, childHeightSpec);}public PullRefreshListview(Context context, AttributeSet attrs,int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);init(context);}public PullRefreshListview(Context context, AttributeSet attrs,int defStyleAttr) {super(context, attrs, defStyleAttr);init(context);}public PullRefreshListview(Context context) {super(context);init(context);}@Overridepublic boolean onTouchEvent(MotionEvent ev) {if (isRefreshable) {switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:if (!isRecored) {isRecored = true;startY = (int) ev.getY();Log.i("startY", startY+"");}break;case MotionEvent.ACTION_UP:if (state != REFRESHING) {if (state == PULL_To_REFRESH) {state = DONE;changeHeaderViewByState();}if (state == RELEASE_To_REFRESH) {state = REFRESHING;changeHeaderViewByState();onLvRefresh();}}isRecored = false;isBack = false;break;case MotionEvent.ACTION_MOVE:int tempY = (int) ev.getY();if (!isRecored) {isRecored = true;startY = tempY;}if ( state != REFRESHING) {if (state == RELEASE_To_REFRESH) {setSelection(0);if (((tempY - startY) / RATIO < headerContentHeight)&& (tempY - startY) > 0) {state = PULL_To_REFRESH;changeHeaderViewByState();} else if ((tempY - startY) <= 0) {state = DONE;changeHeaderViewByState();}}if(state==PULL_To_REFRESH){setSelection(0);if((tempY-startY)/RATIO>=headerContentHeight){state=RELEASE_To_REFRESH;isBack=true;changeHeaderViewByState();}else if(tempY-startY<=0){state=DONE;changeHeaderViewByState();}}// done状态下if (state == DONE) {if (tempY - startY > 0) {state = PULL_To_REFRESH;changeHeaderViewByState();}}// 更新headView的sizeif (state == PULL_To_REFRESH) {headerView.setPadding(0, -1 * headerContentHeight+ (tempY - startY) / RATIO, 0, 0);}// 更新headView的paddingTopif (state == RELEASE_To_REFRESH) {headerView.setPadding(0, (tempY - startY) / RATIO- headerContentHeight, 0, 0);} }break;}}return super.onTouchEvent(ev);}@Overridepublic void onScrollStateChanged(AbsListView view, int scrollState) {// TODO Auto-generated method stub}@Overridepublic void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {if (firstVisibleItem == 0)isRefreshable = true;elseisRefreshable = false;}interface OnRefreshListener {void onRefresh();}public void onRefreshComplete() {state = DONE;lvHeaderLastUpdatedTv.setText("最新更新:" + new Date().toLocaleString());headerView.setPadding(0, -1 * headerContentHeight, 0, 0);}public void onLvRefresh() {if (listener != null)listener.onRefresh();}public void changeHeaderViewByState() {switch (state) {case RELEASE_To_REFRESH: // 表示当前的手势是下拉但是还没有释放,当前手还放在屏幕上lvHeaderArrowlv.setVisibility(View.VISIBLE);lvHeaderProgressBar.setVisibility(View.GONE);lvHeaderTipsTv.setVisibility(View.VISIBLE);lvHeaderLastUpdatedTv.setVisibility(View.VISIBLE);lvHeaderArrowlv.clearAnimation();lvHeaderArrowlv.startAnimation(animation);lvHeaderTipsTv.setText("松开刷新");break;case PULL_To_REFRESH:lvHeaderProgressBar.setVisibility(View.GONE);lvHeaderTipsTv.setVisibility(View.VISIBLE);lvHeaderLastUpdatedTv.setVisibility(View.VISIBLE);lvHeaderArrowlv.clearAnimation();lvHeaderArrowlv.setVisibility(View.VISIBLE);if (isBack) {// 这里表示该状态是从RELEASE_REFRESH状态这个状态isBack = false;lvHeaderArrowlv.clearAnimation();lvHeaderArrowlv.startAnimation(reverseAnimation);lvHeaderTipsTv.setText("下拉刷新");} else {lvHeaderTipsTv.setText("下拉刷新");}break;case REFRESHING:headerView.setPadding(0, 0, 0, 0);lvHeaderProgressBar.setVisibility(View.VISIBLE);lvHeaderArrowlv.clearAnimation();lvHeaderArrowlv.setVisibility(View.GONE);lvHeaderTipsTv.setText("正在刷新...");lvHeaderLastUpdatedTv.setVisibility(View.VISIBLE);break;case DONE:headerView.setPadding(0, -1 * headerContentHeight, 0, 0);lvHeaderProgressBar.setVisibility(View.GONE);lvHeaderArrowlv.clearAnimation();lvHeaderArrowlv.setImageResource(R.drawable.arrow);lvHeaderTipsTv.setText("下拉刷新");lvHeaderLastUpdatedTv.setVisibility(View.VISIBLE);break;}}@Overridepublic void setAdapter(ListAdapter adapter) {// TODO Auto-generated method stubonRefreshComplete();super.setAdapter(adapter);}}
listview的适配器
LvAdapter.java
public class LvAdapter extends BaseAdapter {private List<String> list;private Context context;public LvAdapter(List<String> list, Context context) {this.list = list;this.context = context;}@Overridepublic int getCount() {return list.size();}@Overridepublic Object getItem(int position) {return list.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {TextView tv = new TextView(context.getApplicationContext());tv.setText(list.get(position));return tv;}}
Mainactivity.java
package com.example.pullrefreshlistview;import java.util.ArrayList;import java.util.List;import com.example.pullrefreshlistview.PullRefreshListview.OnRefreshListener;import android.app.Activity;import android.os.AsyncTask;import android.os.Bundle;import android.view.LayoutInflater;import android.view.View;import android.widget.TextView;public class MainActivity extends Activity {private TextView loadMoreTv;private List<String> list;private PullRefreshListview lv;private LvAdapter adapter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);lv = (PullRefreshListview) findViewById(R.id.lv);list = new ArrayList<String>();list.add("新新闻");list.add("loonggg");list.add("samon");list.add("我们都是开发者");list.add("我们都是开发者");list.add("我们都是开发者");list.add("我们都是开发者");list.add("我们都是开发者");list.add("我们都是开发者");list.add("我们都是开发者");list.add("我们都是开发者");adapter = new LvAdapter(list, this);lv.setAdapter(adapter);lv.setListener(new OnRefreshListener() {@Overridepublic void onRefresh() {// TODO Auto-generated method stubnew AsyncTask<Void, Void, Void>() {protected Void doInBackground(Void... params) {try {Thread.sleep(1000);} catch (Exception e) {e.printStackTrace();}for (int i = 0; i < 20; i++) {list.add("刷新后添加的内容");}return null;}@Overrideprotected void onPostExecute(Void result) {adapter.notifyDataSetChanged();lv.onRefreshComplete();}}.execute(null, null, null);}});}}
大体的实现就是这样了,如果需要下载源代码,可以到这里下载:/gxl1240779189/PullRefreshListview.git