Github上有开源的下拉刷新listview(PullToRefresh)大家可以去搜索一下
1、首先继承ListView
package com.example.test;
import java.text.SimpleDateFormat;
import java.util.Date;
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.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.AbsListView.OnScrollListener;
public class MyListView extends ListView implements OnScrollListener {
private static final String TAG = "MyListView";
/**
* 数据加载模式 false为加载底部数据
* true为加载上面数据
*/
private static boolean Mode = false;
/**
* 第一头布局
*/
private View headView;
/**
* 第一按下的Y坐标
*/
private int firstY;
/**
* 头布局高度
*/
private int measuredHeight;
/**
* positionY=-measuredHeight+deltaY;
*/
private int positionY;
/**
* 下拉刷新
*/
private final int DOWN_REFRESH = 0;
/**
* 松开刷新
*/
private final int RELAX_REFRESH = 1;
/**
* 正在刷新
*/
private final int REFRESHING = 2;
/**
* 当前状态,默认是下拉刷新状态
*/
private int CurrState = DOWN_REFRESH;
private RotateAnimation downRa;
private RotateAnimation upRa;
private TextView tv_date;
private TextView tv_title;
private ImageView iv_arrow;
private ProgressBar pb_rotate;
public MyListView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public MyListView(Context context) {
super(context);
initView();
}
private void initView() {
setOnScrollListener(this);
initHeadView();
initAnimation();
initFooterView();
}
private void initFooterView() {
footerView = View.inflate(getContext(), R.layout.list_footer, null);
footerView.measure(0, 0);
footermeasuredHeight = footerView.getMeasuredHeight();
footerView.setPadding(0, -footermeasuredHeight, 0, 0);
addFooterView(footerView);
}
private void initAnimation() {
upRa = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
upRa.setDuration(300);
upRa.setFillAfter(true);
downRa = new RotateAnimation(-180, -360, Animation.RELATIVE_TO_SELF,
0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
downRa.setDuration(300);
downRa.setFillAfter(true);
}
private void initHeadView() {
headView = View.inflate(getContext(), R.layout.list_head, null);
tv_title = (TextView) headView.findViewById(R.id.tv_title);
tv_date = (TextView) headView.findViewById(R.id.tv_date);
iv_arrow = (ImageView) headView.findViewById(R.id.iv_arrow);
pb_rotate = (ProgressBar) headView.findViewById(R.id.pb_rotate);
headView.measure(0, 0);
measuredHeight = headView.getMeasuredHeight();
headView.setPadding(0, -measuredHeight, 0, 0);
addHeaderView(headView);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
firstY = (int) ev.getY();
break;
case MotionEvent.ACTION_UP:
if (CurrState == DOWN_REFRESH) {
headView.setPadding(0, -measuredHeight, 0, 0);
}
if (CurrState == RELAX_REFRESH) {
CurrState = REFRESHING;
reFreshState();
if (listener != null) {
listener.onPullRefresh();
}
}
break;
case MotionEvent.ACTION_MOVE:
int deltaY = (int) ev.getY() - firstY;
positionY = -measuredHeight + deltaY;
Log.e(TAG, "positionY" + positionY);
// 只有在ListView显示第一个,且是向下滑动的时候
if (getFirstVisiblePosition() == 0 && positionY > -measuredHeight) {
headView.setPadding(0, positionY, 0, 0);
// 当完全显示headView并且是当前状态是下拉刷新
if (positionY >= 0 && CurrState == DOWN_REFRESH) {
CurrState = RELAX_REFRESH;
reFreshState();
}
if (CurrState == RELAX_REFRESH && positionY < 0) {
CurrState = DOWN_REFRESH;
reFreshState();
}
return true;
}
break;
default:
break;
}
return super.onTouchEvent(ev);
}
private void reFreshState() {
switch (CurrState) {
case DOWN_REFRESH:
tv_title.setText("下拉刷新");
iv_arrow.startAnimation(downRa);
break;
case RELAX_REFRESH:
tv_title.setText("松开刷新");
iv_arrow.startAnimation(upRa);
break;
case REFRESHING:
iv_arrow.clearAnimation();
iv_arrow.setVisibility(View.INVISIBLE);
pb_rotate.setVisibility(View.VISIBLE);
tv_title.setText("正在刷新....");
headView.setPadding(0, 0, 0, 0);
break;
default:
break;
}
}
private String getCurrTime() {
SimpleDateFormat format = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
return format.format(new Date());
}
private OnReFreshListener listener;
private View footerView;
private int footermeasuredHeight;
public void setOnReFreshListener(OnReFreshListener freshListener) {
this.listener = freshListener;
}
public interface OnReFreshListener {
/**
* 下拉刷新
*/
void onPullRefresh();
/**
* 向下滑动加载更多
*/
void onLoadMore();
}
/**
* 当完成加载数据的时候调用,MyListView自己本身不知道什么时候加载完数据
*/
public void completeLoading() {
if (Mode) {
footerView.setPadding(0, -footermeasuredHeight, 0, 0);
Mode=false;
}else {
headView.setPadding(0, -measuredHeight, 0, 0);
tv_date.setText("最后一次更新时间" + getCurrTime());
iv_arrow.setVisibility(View.VISIBLE);
pb_rotate.setVisibility(View.INVISIBLE);
tv_title.setText("下拉刷新");
CurrState = DOWN_REFRESH;
}
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
switch (scrollState) {
case OnScrollListener.SCROLL_STATE_IDLE:
if (getLastVisiblePosition()==(getCount()-1)&&!Mode) {
footerView.setPadding(0, 0, 0, 0);
Mode=true;
setSelection(getCount());
if (listener!=null) {
listener.onLoadMore();
}
}
break;
case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
break;
case OnScrollListener.SCROLL_STATE_FLING:
break;
default:
break;
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
}
}
在构造函数里面绑定了onScrollListener,和初始化了一些数据,
onTouchEvent里面根据触发的条件判断,代码已经有注释,比较简单。
那么下面看一下MainActivity里面是如何实现的
package com.example.test;
import java.util.ArrayList;
import java.util.List;
import com.example.test.MyListView.OnReFreshListener;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
public class MainActivity extends Activity {
private MyListView myListView;
private List<String > mList;
private Handler mHandler=new Handler(){
public void handleMessage(android.os.Message msg) {
myadapter.notifyDataSetChanged();
myListView.completeLoading();
};
};
private Myadapter myadapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
}
private void initData() {
mList = new ArrayList<String>();
for (int i = 0; i < 20; i++) {
mList.add("这是ListView第"+i+"个数据");
}
myadapter = new Myadapter();
myListView.setAdapter(myadapter);
myListView.setOnReFreshListener(new OnReFreshListener() {
@Override
public void onPullRefresh() {
getDataFromService(true);
}
@Override
public void onLoadMore() {
getDataFromService(false);
}
});
}
protected void getDataFromService(final boolean loadingMode) {
new Thread(new Runnable() {
@Override
public void run() {
SystemClock.sleep(2000);//模拟请求服务器的一个时间长度
if (loadingMode) {
mList.add(0,"通过下拉从服务器返回的数据");
}else {
mList.add("底部更新从服务器返回数据");
}
mHandler.sendEmptyMessage(0);
}
}).start();
}
private void initView() {
myListView = (MyListView) findViewById(R.id.myListView);
}
class Myadapter extends BaseAdapter{
@Override
public int getCount() {
return mList.size();
}
@Override
public Object getItem(int position) {
return mList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView textView=new TextView(MainActivity.this);
textView.setText(mList.get(position));
textView.setPadding(20, 20, 20, 20);
textView.setTextSize(17);
return textView;
}
}
}
自定义了一个线程模拟请求服务器的的时间,当请求完成之后,通知适配器,更新数据,必须在UI线程中执行,让后通知ListView,我已经完成了数据的加载。
布局文件 :activity_main
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.test.MainActivity" >
<com.example.test.MyListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/myListView"/>
</RelativeLayout>
布局文件 :list_footer
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center" >
<ProgressBar
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:indeterminate="true"
android:indeterminateDrawable="@drawable/indicate_rotate"
android:indeterminateDuration="1000" />
<TextView
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:layout_marginLeft="15dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="加载更多..."
android:textColor="#000"
android:textSize="22sp"/>
</LinearLayout>
布局文件 ;list_header
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
>
<RelativeLayout
android:layout_marginBottom="10dp"
android:layout_marginTop="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<ImageView
android:id="@+id/iv_arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="@drawable/indicator_arrow" />
<ProgressBar
android:id="@+id/pb_rotate"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_centerInParent="true"
android:visibility="gone"
android:indeterminateDrawable="@drawable/indicate_rotate"
android:indeterminateDuration="1000" />
</RelativeLayout>
<LinearLayout
android:layout_marginBottom="10dp"
android:layout_marginTop="10dp"
android:layout_marginLeft="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"
>
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下拉刷新"
android:textColor="#000"
android:textSize="22sp"/>
<TextView
android:id="@+id/tv_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="最后刷新时间2016-03-31 14:58:17"
android:textColor="#aaa"/>
</LinearLayout>
</LinearLayout>
自定义的动画:indicate_rotate.xml
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="0"
android:toDegrees="360"
android:pivotX="50%"
android:pivotY="50%"
android:drawable="@drawable/indicate_rotate_drawable" >
</rotate>