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,假如手机又上移会变成从新变成DONE
public 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);
}
@Override
public 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的size
if (state == PULL_To_REFRESH) {
headerView.setPadding(0, -1 * headerContentHeight
+ (tempY - startY) / RATIO, 0, 0);
}
// 更新headView的paddingTop
if (state == RELEASE_To_REFRESH) {
headerView.setPadding(0, (tempY - startY) / RATIO
- headerContentHeight, 0, 0);
}
}
break;
}
}
return super.onTouchEvent(ev);
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
// TODO Auto-generated method stub
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if (firstVisibleItem == 0)
isRefreshable = true;
else
isRefreshable = 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;
}
}
@Override
public void setAdapter(ListAdapter adapter) {
// TODO Auto-generated method stub
onRefreshComplete();
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;
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public 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;
@Override
protected 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() {
@Override
public void onRefresh() {
// TODO Auto-generated method stub
new 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;
}
@Override
protected void onPostExecute(Void result) {
adapter.notifyDataSetChanged();
lv.onRefreshComplete();
}
}.execute(null, null, null);
}
});
}
}
大体的实现就是这样了,如果需要下载源代码,可以到这里下载:https://github.com/gxl1240779189/PullRefreshListview.git