当前位置: 代码迷 >> Android >> Android实战简易课程-第五十四枪(通过实现OnScrollListener接口实现下拉刷新功能)
  详细解决方案

Android实战简易课程-第五十四枪(通过实现OnScrollListener接口实现下拉刷新功能)

热度:95   发布时间:2016-04-27 23:02:58.0
Android实战简易教程-第五十四枪(通过实现OnScrollListener接口实现下拉刷新功能)

上一篇文章Android实战简易教程-第五十三枪(通过实现OnScrollListener接口实现上拉加载更多功能)讲述了如何实现上拉加载更多的功能,本篇,我们在上一篇的基础上实现下拉刷新功能。主要通过对滚动状态和手势监听实现这一功能,下面我们看一下代码:

1.header.xml:

<?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="vertical" >    <RelativeLayout        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:paddingBottom="10dip"        android:paddingTop="10dip" >        <LinearLayout            android:id="@+id/layout"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_centerInParent="true"            android:gravity="center"            android:orientation="vertical" >            <TextView                android:id="@+id/tip"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:text="下拉可以刷新!" />            <TextView                android:id="@+id/lastupdate_time"                android:layout_width="wrap_content"                android:layout_height="wrap_content" />        </LinearLayout>        <ImageView            android:id="@+id/arrow"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_toLeftOf="@id/layout"            android:layout_marginRight="20dip"            android:src="@drawable/pull_to_refresh_arrow" />        <ProgressBar            android:id="@+id/progress"            style="?android:attr/progressBarStyleSmall"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_toLeftOf="@id/layout"            android:layout_marginRight="20dip"            android:visibility="gone" />    </RelativeLayout></LinearLayout>

2.LoadListView.java:

package com.example.listviewscrolldemo;import java.text.SimpleDateFormat;import java.util.Date;import android.content.Context;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.RotateAnimation;import android.widget.AbsListView;import android.widget.AbsListView.OnScrollListener;import android.widget.ImageView;import android.widget.ListView;import android.widget.ProgressBar;import android.widget.TextView;public class LoadListView extends ListView implements OnScrollListener {	private int lastVisibleItem;// 最后一个可见项	private int totalItems;// 所有项	private int firstVisibleItem;// 第一可见项	private View footer, header;// 底部布局	private Boolean isLoading = false;	private Boolean isRemark = false;// 判断在当前页面的最顶端并下滑;	private int startY;// Y坐标值	private ILoadListener iListener;	private RLoadListener rListener;	private int scrollState;// 当前滚动状态;全局变量	private int headerHeight;// 顶部布局文件的高度;	final int NONE = 0;// 正常状态;	final int PULL = 1;// 提示下拉状态;	final int RELESE = 2;// 提示释放状态;	final int REFLASHING = 3;// 刷新状态;	private int state;// 判断当前状态	public LoadListView(Context context) {		super(context);		initView(context);	}	public LoadListView(Context context, AttributeSet attrs) {		super(context, attrs);		initView(context);	}	public LoadListView(Context context, AttributeSet attrs, int defStyleAttr) {		super(context, attrs, defStyleAttr);		initView(context);	}	/**	 * 添加底部加载提示到布局Listview	 * 	 * @param context	 */	private void initView(Context context) {		LayoutInflater inflater = LayoutInflater.from(context);		footer = inflater.inflate(R.layout.footer, null);		header = inflater.inflate(R.layout.header_layout, null);		footer.findViewById(R.id.ll_footer).setVisibility(View.GONE);// 首先设置加载提示不可见		measureView(header);		headerHeight = header.getMeasuredHeight();		Log.i("tag", "headerHeight = " + headerHeight);		topPadding(-headerHeight);		this.addFooterView(footer);		this.addHeaderView(header);		this.setOnScrollListener(this);// 设置滚动监听	}	/**	 * 通知父布局,占用的宽,高;	 * 	 * @param view	 */	private void measureView(View view) {		ViewGroup.LayoutParams p = view.getLayoutParams();		if (p == null) {			p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);		}		int width = ViewGroup.getChildMeasureSpec(0, 0, p.width);		int height;		int tempHeight = p.height;		if (tempHeight > 0) {			height = MeasureSpec.makeMeasureSpec(tempHeight, MeasureSpec.EXACTLY);		} else {			height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);		}		view.measure(width, height);	}	/**	 * 设置header 布局 上边距;	 * 	 * @param topPadding	 */	private void topPadding(int topPadding) {		header.setPadding(header.getPaddingLeft(), topPadding, header.getPaddingRight(), header.getPaddingBottom());		header.invalidate();	}	@Override	public void onScrollStateChanged(AbsListView view, int scrollState) {		this.scrollState = scrollState;		if (lastVisibleItem == totalItems && scrollState == SCROLL_STATE_IDLE) {			if (!isLoading) {// 判断不是正在加载!				footer.findViewById(R.id.ll_footer).setVisibility(View.VISIBLE);// 首先设置加载提示可见				iListener.onLoad();				isLoading = true;			}		}	}	@Override	public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {		this.lastVisibleItem = firstVisibleItem + visibleItemCount;		this.totalItems = totalItemCount;		this.firstVisibleItem = firstVisibleItem;	}	// 传递	public void setInterface(ILoadListener iListener) {		this.iListener = iListener;	}	public void setRefreshInterface(RLoadListener rListener) {		this.rListener = rListener;	}	/**	 * 加载更多数据的回调接口	 * 	 * @author Administrator	 *	 */	public interface ILoadListener {		public void onLoad();	}	/**	 * 下拉刷新回调接口	 * 	 * @author Administrator	 *	 */	public interface RLoadListener {		public void onRefresh();	}	// 加载完毕	public void loadCompleted() {		isLoading = false;		footer.findViewById(R.id.ll_footer).setVisibility(View.GONE);	}	@Override	public boolean onTouchEvent(MotionEvent ev) {		// TODO Auto-generated method stub		switch (ev.getAction()) {		case MotionEvent.ACTION_DOWN://下拉			if (firstVisibleItem == 0) {				isRemark = true;				startY = (int) ev.getY();			}			break;		case MotionEvent.ACTION_MOVE://移动			onMove(ev);			break;		case MotionEvent.ACTION_UP://上拉			if (state == RELESE) {				state = REFLASHING;				// 加载最新数据;				reflashViewByState();				rListener.onRefresh();			} else if (state == PULL) {				state = NONE;				isRemark = false;				reflashViewByState();			}			break;		}		return super.onTouchEvent(ev);	}	/**	 * 判断移动过程操作;	 * 	 * @param ev	 */	private void onMove(MotionEvent ev) {		if (!isRemark) {			return;		}		int tempY = (int) ev.getY();		int space = tempY - startY;		int topPadding = space - headerHeight;		switch (state) {		case NONE:			if (space > 0) {// 向下滑动				state = PULL;				reflashViewByState();			}			break;		case PULL:			topPadding(topPadding);			if (space > headerHeight + 30 && scrollState == SCROLL_STATE_TOUCH_SCROLL) {// 如果正在滚动切超过30				state = RELESE;				reflashViewByState();			}			break;		case RELESE:			topPadding(topPadding);			if (space < headerHeight + 30) {				state = PULL;				reflashViewByState();			} else if (space <= 0) {				state = NONE;				isRemark = false;				reflashViewByState();			}			break;		}	}	/**	 * 根据当前状态,改变界面显示;	 */	private void reflashViewByState() {		TextView tip = (TextView) header.findViewById(R.id.tip);		ImageView arrow = (ImageView) header.findViewById(R.id.arrow);		ProgressBar progress = (ProgressBar) header.findViewById(R.id.progress);		RotateAnimation anim = new RotateAnimation(0, 180, RotateAnimation.RELATIVE_TO_SELF, 0.5f,				RotateAnimation.RELATIVE_TO_SELF, 0.5f);		anim.setDuration(500);		anim.setFillAfter(true);		RotateAnimation anim1 = new RotateAnimation(180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f,				RotateAnimation.RELATIVE_TO_SELF, 0.5f);		anim1.setDuration(500);		anim1.setFillAfter(true);		/**		 * 四种状态		 */		switch (state) {		case NONE:			arrow.clearAnimation();			topPadding(-headerHeight);			break;		case PULL:			arrow.setVisibility(View.VISIBLE);			progress.setVisibility(View.GONE);			tip.setText("下拉可以刷新!");			arrow.clearAnimation();			arrow.setAnimation(anim1);			break;		case RELESE:			arrow.setVisibility(View.VISIBLE);			progress.setVisibility(View.GONE);			tip.setText("松开可以刷新!");			arrow.clearAnimation();			arrow.setAnimation(anim);			break;		case REFLASHING:			topPadding(50);			arrow.setVisibility(View.GONE);			progress.setVisibility(View.VISIBLE);			tip.setText("正在刷新...");			arrow.clearAnimation();			break;		}	}	/**	 * 获取完数据;	 */	public void reflashComplete() {		state = NONE;		isRemark = false;		reflashViewByState();		TextView lastupdatetime = (TextView) header.findViewById(R.id.lastupdate_time);		SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss");		Date date = new Date(System.currentTimeMillis());		String time = format.format(date);		lastupdatetime.setText(time);	}}

这里我们定义了四种状态:

        final int NONE = 0;// 正常状态;
final int PULL = 1;// 提示下拉状态;(下拉距离比较短,此时松开不刷新)
final int RELESE = 2;// 提示释放状态;(下拉距离较长,此时松开刷新)
final int REFLASHING = 3;// 刷新状态;(松开状态,正在刷新)

       这四种状态决定了header布局的不同展示效果,具体由reflashViewByState()方法实现。

       onMove()方法通过判断移动过程,实现四种状态之间的转换。

package com.example.listviewscrolldemo;import java.util.ArrayList;import java.util.List;import com.example.listviewscrolldemo.LoadListView.ILoadListener;import com.example.listviewscrolldemo.LoadListView.RLoadListener;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.widget.ArrayAdapter;public class MainActivity extends Activity implements ILoadListener, RLoadListener {	private LoadListView mListView;	private ArrayAdapter<String> adapter;	private List<String> datas;	@Override	protected void onCreate(Bundle savedInstanceState) {		super.onCreate(savedInstanceState);		setContentView(R.layout.activity_main);		initViews();		initDatas();	}	private void initDatas() {		for (int i = 1; i < 21; i++) {			datas.add("数据" + i + "");		}	}	private void initMoreDatas() {		for (int i = 1; i < 3; i++) {			datas.add("新数据" + i + "");		}	}	private void initViews() {		mListView = (LoadListView) findViewById(R.id.lv_main);		mListView.setInterface(this);		mListView.setRefreshInterface(this);		datas = new ArrayList<String>();		adapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, datas);		// adapter=new		// ArrayAdapter<String>(MainActivity.this,android.R.layout.simple_list_item_1);		mListView.setAdapter(adapter);	}	@Override	public void onLoad() {		// 添加延时效果		Handler handler = new Handler();		handler.postDelayed(new Runnable() {			public void run() {				initMoreDatas();// 获取更多数据				adapter.notifyDataSetChanged();// 刷新ListView				mListView.loadCompleted();// 隐藏加载提示			}		}, 2000);	}	@Override	public void onRefresh() {		// 添加延时效果		Handler handler = new Handler();		handler.postDelayed(new Runnable() {			public void run() {				initRefreshDatas();// 获取更多数据				adapter.notifyDataSetChanged();// 刷新ListView				mListView.reflashComplete();// 隐藏刷新提示			}		}, 2000);	}	private void initRefreshDatas() {		// datas.add("新数据" + i + "");		datas.add(0, "下拉刷新数据" + 1 + "");//此方法插入表头		datas.add(0, "下拉刷新数据" + 2 + "");	}}

运行本实例如下:


届时,上拉加载和下拉刷新功能都实现了。

喜欢的朋友关注我吧!谢谢

源码下载



版权声明:本文为博主原创文章,未经博主允许不得转载。

2楼qq_234333473天前 11:06
菜鸟围观 0.0
Re: yayun0516前天 11:33
回复qq_23433347n欢迎围观
1楼u0102027975天前 22:33
膜拜,大神!
Re: yayun05165天前 08:49
回复u010202797n共同学习,嘿嘿
  相关解决方案