自定义下拉刷新ListView

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>





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值