Android开发之自定义控件--ListView的下拉刷新功能

继承ListView

package com.itheima18.listview;

import java.util.Date;

import com.itheima18.listview.ListView.OnRefreshListener;

import android.content.Context;
import android.hardware.Camera.Parameters;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.ProgressBar;
import android.widget.TextView;

public class ListView extends android.widget.ListView implements
		OnScrollListener {
	
	private View headView;
	private ImageView arrow;
	private ProgressBar progressBar;
	private TextView title;
	private TextView last_update;
	private int headContentWidth;
	private int headContentHeight;
	private int firstVisibleIndex;//当前页面中 listView第一个可以的item的下标
	private Animation animation;
	private RotateAnimation animation2;
	private float startY;// 记录headView计将拉动下拉时候的坐标点
	private boolean isRecord = false;//startY是否已被记录   true   false
	private float tempY;
	
	private static final int RATIO = 3;//实际拉动距离 与 下拉刷新控件下拉距离之比
	
	private static final int PULL_TO_REFRESH = 0;//下拉刷新
	private static final int RELEASE_TO_REFRESH = 1;//松开刷新
	private static final int REFRESHING = 2;//正在刷新中
	private static final int DONE = 3;//刷新完成
	private int state; //当前下拉刷新控件的状态
	private boolean isBack = false;
	private OnRefreshListener refreshListener;//刷新监听器
	
	

	public ListView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		
		init(context);
	}

	public ListView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(context);
	}

	public ListView(Context context) {
		super(context);
		init(context);
	}

	private void init(Context context) {
		
	//listView和header合并
		//加载header页面
		headView = View.inflate(context, R.layout.head, null);
		
		arrow = (ImageView) headView.findViewById(R.id.arrow);
		progressBar = (ProgressBar) headView.findViewById(R.id.progressBar);
		title = (TextView) headView.findViewById(R.id.title);
		last_update = (TextView) headView.findViewById(R.id.last_update);
		
		arrow.setMinimumWidth(70);
		arrow.setMinimumHeight(50);
		
		//测量headView尺寸大小
		measureView(headView);
		
		//测量headView 之后的宽高
		headContentWidth = headView.getMeasuredWidth();
		headContentHeight = headView.getMeasuredHeight();
		
		//headView隐藏在页面上方
		headView.setPadding(0, -1 * headContentHeight, 0, 0);
		//刷新headView
		headView.invalidate();
		
		//listView和header绑定
		addHeaderView(headView);
		
//		listView.addHeader(view);
//		listView.addFooter(View);
		
		//添加滑动监听
		setOnScrollListener(this);
		
	//箭头旋转动画
		//右--> 左
		animation = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
		animation.setDuration(250);
		animation.setFillAfter(true);
		animation.setInterpolator(new LinearInterpolator());//动画窜改器
		
		//左--> 右
		animation2 = new RotateAnimation(-180, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
		animation2.setDuration(200);
		animation2.setFillAfter(true);
		animation2.setInterpolator(new LinearInterpolator());//动画窜改器
		
		/**
		 * Interpolator 定义了动画的变化速度,可以实现匀速、正加速、负加速、无规则变加速等;
			AccelerateDecelerateInterpolator,延迟减速,在动作执行到中间的时候才执行该特效。
			AccelerateInterpolator, 会使慢慢以(float)的参数降低速度。
			LinearInterpolator,平稳不变的
			DecelerateInterpolator,在中间加速,两头慢
			CycleInterpolator,曲线运动特效,要传递float型的参数。
		 */
	}
	
	
	//测量headView尺寸大小
	private void measureView(View child) {//headView.width\ height
		
		ViewGroup.LayoutParams lp = child.getLayoutParams();
		
		if(lp == null){
			lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
		}
		
		//测量控件的宽高
		// 宽度childMeasureWidth  -= headView宽度
		//高度childMeasureHeight == headView 高度
		
		//宽度
		int childMeasureWidth = ViewGroup.getChildMeasureSpec(0, 0, lp.width);
		
		//高度
		int childMeasureHeight;
		
		
		if(lp.height > 0){
			//headView 有内部控件   高度 lp.height
			//int size 测量结果返回值
			//int mode 测量的模式  (lp.height > 0 EXACTLY 适当的模式,    lp.height <= 0 UNSPECIFIED 未指定的模式 )
			childMeasureHeight = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);
		}  else {
			//lp == null , headView 没有内部控件	高度 0
			childMeasureHeight = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
		}
		
		//记录测量后的宽高
		child.measure(childMeasureWidth, childMeasureHeight);
		
	}

	@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) {
		// TODO Auto-generated method stub
		
		firstVisibleIndex = firstVisibleItem;

	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			
			if(firstVisibleIndex == 0 && !isRecord){
				startY = event.getY();
				
				isRecord = true;
			}
			
			
			break;
		case MotionEvent.ACTION_MOVE:
			tempY = event.getY();
			
			if(firstVisibleIndex == 0 && !isRecord){
				startY = tempY;
				
				isRecord = true;
			}
			//---------------------
			if(state != REFRESHING){
				
				if(state == PULL_TO_REFRESH){//下拉刷新
					//选中第0个条目,防止长按事件出现的bug
					setSelection(0);
					
					
					if((tempY - startY) <0 ){//向上推了  整个headVIew都不见了  
						//下拉刷新  --> 刷新完成
						state = DONE;
						
						//改变headView控件显示
						changeHeadViewState();
					} else if((tempY - startY) /RATIO > headContentHeight){
						//下拉刷新  --> 松开刷新
						state = RELEASE_TO_REFRESH;

						changeHeadViewState();
					}
				}
				
				if(state == RELEASE_TO_REFRESH){//松开刷新
					
					setSelection(0);

					if((tempY - startY) /RATIO < headContentHeight && (tempY - startY) > 0){
						//松开刷新 --> 下拉刷新 
						state = PULL_TO_REFRESH;
						
						isBack = true;
						changeHeadViewState();
					}
				}
				
				if(state == DONE){//刷新完成
					if((tempY - startY) >0 ){
						//刷新完成  --> 下拉刷新 
						state = PULL_TO_REFRESH;
						changeHeadViewState();
					}
				}
				
				//tempY - startY
				//动态的指定 headView上边  与 页面的上边距的实际距离
				headView.setPadding(0, (int) (tempY - startY)/RATIO - headContentHeight, 0, 0);
			}
			
			break;
		case MotionEvent.ACTION_UP:
			
			if(state != REFRESHING){
				
				if(state == PULL_TO_REFRESH){//下拉刷新
					//下拉刷新 回到  刷新完成
					state = DONE;
					changeHeadViewState();
				}
				
				if(state == RELEASE_TO_REFRESH){//松开刷新
					//松开刷新 进入到正在刷新
					
					state = REFRESHING;
					changeHeadViewState();
					
					//访问服务器刷新数据
					onRefresh();
					
				}
			}

			break;

		}
		
		invalidate();
		return true;
	}

	//改变headView控件显示
	private void changeHeadViewState() {
		switch (state) {
		case PULL_TO_REFRESH://下拉刷新
			arrow.setVisibility(View.VISIBLE);
			progressBar.setVisibility(View.GONE);
			title.setVisibility(View.VISIBLE);
			last_update.setVisibility(View.VISIBLE);
			
			title.setText("下拉刷新");
			arrow.clearAnimation();
			if(isBack ){//是否从松开刷新回到的下拉刷新
				arrow.startAnimation(animation2);
				isBack = false;
			}
			
			break;
		case RELEASE_TO_REFRESH://松开刷新
			arrow.setVisibility(View.VISIBLE);
			progressBar.setVisibility(View.GONE);
			title.setVisibility(View.VISIBLE);
			last_update.setVisibility(View.VISIBLE);
			
			title.setText("松开刷新");
			arrow.clearAnimation();
			arrow.startAnimation(animation);
			
			break;
		case REFRESHING://正在刷新
			arrow.setVisibility(View.GONE);
			progressBar.setVisibility(View.VISIBLE);
			title.setVisibility(View.VISIBLE);
			last_update.setVisibility(View.VISIBLE);
			
			title.setText("正在刷新中...");
			arrow.clearAnimation();
			
			headView.setPadding(0, 0, 0, 0);
			
			break;
		case DONE://刷新完成
			arrow.setVisibility(View.VISIBLE);
			progressBar.setVisibility(View.GONE);
			title.setVisibility(View.VISIBLE);
			last_update.setVisibility(View.VISIBLE);
			
			title.setText("下拉刷新");
			arrow.clearAnimation();
			
			headView.setPadding(0, -1 * headContentHeight, 0, 0);
			break;

		}
		
	}
	

	//对外提供刷新监听操作
	interface OnRefreshListener{
		
		abstract void onRefresh();
	}
	
	public void setOnRefreshListener(OnRefreshListener listener){
		refreshListener = listener;
	}
	
	
	
	
	//访问服务器刷新数据
	private void onRefresh() {
		refreshListener.onRefresh();
	}

	//页面刷新完成
	//更新  headView 状态  	更新时间
	public void onRefreshComplete() {
		state = DONE;
		changeHeadViewState();
		
		last_update.setText("更新于: " + new Date().toLocaleString());
	}
	
	@Override
	public void setAdapter(ListAdapter adapter) {
		super.setAdapter(adapter);
		
		last_update.setText("更新于: " + new Date().toLocaleString());
	}
	
}

 

使用ListView

package com.itheima18.listview;

import java.util.ArrayList;

import com.itheima18.listview.ListView.OnRefreshListener;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

public class MainActivity extends Activity {

	private ListView listView;
	private MyAdapter adapter;
	private ArrayList data;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		initData();
		
		listView = (ListView) findViewById(R.id.listView);
		adapter = new MyAdapter();
		listView.setAdapter(adapter);
		
		//添加滑动刷新监听器 
		listView.setOnRefreshListener(new OnRefreshListener() {
			
			@Override
			public void onRefresh() {
				
				//访问服务器 获取数据
				new AsyncTask() {

					@Override
					protected Void doInBackground(Void... params) {
						
						data.add("新数据");
						
						SystemClock.sleep(2000);
						
						return null;
					}

					@Override
					protected void onPostExecute(Void result) {
						// TODO Auto-generated method stub
						super.onPostExecute(result);
						
						listView.onRefreshComplete();

						adapter.notifyDataSetChanged();
					}
					
				}.execute();
				
			}
		});
	}

	private void initData() {
		
		data = new ArrayList();
		data.add("a");
		data.add("b");
		data.add("c");
		data.add("d");
		data.add("e");
		data.add("f");
	}

	private class MyAdapter extends BaseAdapter{

		@Override
		public int getCount() {
			// TODO Auto-generated method stub
			return data.size();
		}

		@Override
		public Object getItem(int position) {
			// TODO Auto-generated method stub
			return data.get(position);
		}

		@Override
		public long getItemId(int position) {
			// TODO Auto-generated method stub
			return position;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			// TODO Auto-generated method stub
			TextView textView = new TextView(getApplicationContext());
			textView.setText(data.get(position));
			return textView;
		}
		
	}

}

 

布局文件



    


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值