你的位置:首页 > 操作系统

[操作系统]Android—自定义控件实现ListView下拉刷新


这篇博客为大家介绍一个android常见的功能——ListView下拉刷新(参考自他人博客,网址忘记了,阅读他的代码自己理解注释的,希望能帮助到大家):

首先下拉未松手时候手机显示这样的界面:

下面的代码是自定的扎样的控件:

package com.dhsr.smartID.view;import android.content.Context;import android.util.AttributeSet;import android.view.Gravity;import android.view.LayoutInflater;import android.view.View;import android.view.animation.Animation;import android.view.animation.RotateAnimation;import android.widget.ImageView;import android.widget.LinearLayout;import android.widget.ProgressBar;import android.widget.TextView;import com.example.sirelinkscanapp.R;/** * 自定义控件,完成下拉时候ListView显示“图标及提示正在刷新……”的布局 * * @author cyf * */public class XListViewHeader extends LinearLayout {	private LinearLayout mContainer;	// 图片	private ImageView mArrowImageView;	// 圆形进度条	private ProgressBar mProgressBar;	private TextView mHintTextView;	// 状态	private int mState = STATE_NORMAL;	// 动画	private Animation mRotateUpAnim;	private Animation mRotateDownAnim;	private final int ROTATE_ANIM_DURATION = 180;	// 正常	public final static int STATE_NORMAL = 0;	// 准备刷新	public final static int STATE_READY = 1;	// 刷新中	public final static int STATE_REFRESHING = 2;	public XListViewHeader(Context context) {		super(context);		initView(context);	}	/**	 * @param context	 * @param attrs	 */	public XListViewHeader(Context context, AttributeSet attrs) {		super(context, attrs);		initView(context);	}	/**	 * “ 松开即可刷新……正在刷新……”的布局	 * 	 * @param context	 */	private void initView(Context context) {		// 初始情况,设置下拉刷新view高度为0		LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(				LayoutParams.MATCH_PARENT, 0);		mContainer = (LinearLayout) LayoutInflater.from(context).inflate(				R.layout.xlistview_header, null);		// 加载视图		addView(mContainer, lp);		// 居中方式		setGravity(Gravity.BOTTOM);		// 初始化控件		mArrowImageView = (ImageView) findViewById(R.id.xlistview_header_arrow);		mHintTextView = (TextView) findViewById(R.id.xlistview_header_hint_textview);		mProgressBar = (ProgressBar) findViewById(R.id.xlistview_header_progressbar);		// 设置动画		mRotateUpAnim = new RotateAnimation(0.0f, -180.0f,				Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,				0.5f);		mRotateUpAnim.setDuration(ROTATE_ANIM_DURATION);		mRotateUpAnim.setFillAfter(true);		mRotateDownAnim = new RotateAnimation(-180.0f, 0.0f,				Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,				0.5f);		mRotateDownAnim.setDuration(ROTATE_ANIM_DURATION);		mRotateDownAnim.setFillAfter(true);	}	/**	 * 根据下拉状态执行相应的功能,开始以及停止相应的动画	 * 	 * @param state	 */	public void setState(int state) {		if (state == mState)			return;		if (state == STATE_REFRESHING) { // 显示进度			mArrowImageView.clearAnimation();			mArrowImageView.setVisibility(View.INVISIBLE);			mProgressBar.setVisibility(View.VISIBLE);		} else { // 显示箭头图片			mArrowImageView.setVisibility(View.VISIBLE);			mProgressBar.setVisibility(View.INVISIBLE);		}		switch (state) {				case STATE_NORMAL:			if (mState == STATE_READY) {				// 开始动画				mArrowImageView.startAnimation(mRotateDownAnim);			}			//刷新中			if (mState == STATE_REFRESHING) {				// 清除动画				mArrowImageView.clearAnimation();			}			mHintTextView.setText(R.string.xlistview_header_hint_normal);			break;		case STATE_READY:			if (mState != STATE_READY) {				mArrowImageView.clearAnimation();				mArrowImageView.startAnimation(mRotateUpAnim);				mHintTextView.setText(R.string.xlistview_header_hint_ready);			}			break;		case STATE_REFRESHING:			mHintTextView.setText(R.string.xlistview_header_hint_loading);			break;		default:		}		mState = state;	}  	public void setVisiableHeight(int height) {		if (height < 0)			height = 0;		LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mContainer				.getLayoutParams();		lp.height = height;		mContainer.setLayoutParams(lp);	}	public int getVisiableHeight() {		return mContainer.getHeight();	}}

 接下来需要自定义自己的ListView继承与android本身的ListView,方便自己添加新的方法。

package com.dhsr.smartID.view;import android.content.Context;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.view.ViewTreeObserver.OnGlobalLayoutListener;import android.view.animation.DecelerateInterpolator;import android.widget.AbsListView;import android.widget.AbsListView.OnScrollListener;import android.widget.ListAdapter;import android.widget.ListView;import android.widget.RelativeLayout;import android.widget.Scroller;import android.widget.TextView;import com.example.sirelinkscanapp.R;/** * 自定义ListView * * @author cyf * */public class XListView extends ListView implements OnScrollListener {	private final String TAG = "XListView";	private float mLastY = -1;	private Scroller mScroller;	// 滑动	private OnScrollListener mScrollListener;	// 为外界创建监听	private IXListViewListener mListViewListener;	// 刚才定义的自定义控件	private XListViewHeader mHeaderView;	private RelativeLayout mHeaderViewContent;	private TextView mHeaderTimeView;	private int mHeaderViewHeight; // header view's height	private boolean mEnablePullRefresh = true;	private boolean mPullRefreshing = false; // is refreashing.	private boolean mEnablePullLoad;	private boolean mPullLoading;	private boolean mIsFooterReady = false;	// total list items, used to detect is at the bottom of listview.	private int mTotalItemCount;	// for mScroller, scroll back from header or footer.	private int mScrollBack;	private final static int SCROLLBACK_HEADER = 0;	private final static int SCROLLBACK_FOOTER = 1;	private final static int SCROLL_DURATION = 400; // scroll back duration	private final static int PULL_LOAD_MORE_DELTA = 50; // when pull up >= 50px														// at bottom, trigger														// load more.	private final static float OFFSET_RADIO = 1.8f; // support iOS like pull													// feature.	/**	 * @param context	 */	public XListView(Context context) {		super(context);		initWithContext(context);	}	public XListView(Context context, AttributeSet attrs) {		super(context, attrs);		initWithContext(context);	}	public XListView(Context context, AttributeSet attrs, int defStyle) {		super(context, attrs, defStyle);		initWithContext(context);	}	/**	 * 初始化控件	 * 	 * @param context	 */	private void initWithContext(Context context) {		mScroller = new Scroller(context, new DecelerateInterpolator());		super.setOnScrollListener(this);		mHeaderView = new XListViewHeader(context);		mHeaderViewContent = (RelativeLayout) mHeaderView				.findViewById(R.id.xlistview_header_content);		mHeaderTimeView = (TextView) mHeaderView				.findViewById(R.id.xlistview_header_time);		addHeaderView(mHeaderView, null, false);		mHeaderView.getViewTreeObserver().addOnGlobalLayoutListener(				new OnGlobalLayoutListener() {					@Override					public void onGlobalLayout() {						mHeaderViewHeight = mHeaderViewContent.getHeight();						getViewTreeObserver()								.removeGlobalOnLayoutListener(this);					}				});	}	@Override	public void setAdapter(ListAdapter adapter) {		// make sure XListViewFooter is the last footer view, and only add once.		if (mIsFooterReady == false) {			if (mEnablePullLoad) {				mIsFooterReady = true;				// addFooterView(mFooterView);			}		}		super.setAdapter(adapter);	}	public void setPullRefreshEnable(boolean enable) {		mEnablePullRefresh = enable;		if (!mEnablePullRefresh) { // disable, hide the content			mHeaderViewContent.setVisibility(View.INVISIBLE);		} else {			mHeaderViewContent.setVisibility(View.VISIBLE);		}	}	/**	 * 停止刷新	 */	public void stopRefresh() {		if (mPullRefreshing == true) {			mPullRefreshing = false;			resetHeaderHeight();		}	}	// 可使进入Activity时便执行下拉刷新	public void startRefresh() {		if (mPullRefreshing == false) {			mPullRefreshing = true;			mHeaderView.setState(XListViewHeader.STATE_REFRESHING);			mHeaderView.setVisiableHeight(90);			if (mListViewListener != null) {				mListViewListener.onRefresh();			}		}	}	/**	 * stop load more, reset footer view.	 */	public void stopLoadMore() {		if (mPullLoading == true) {			mPullLoading = false;		}	}	/**	 * set last refresh time	 * 	 * @param time	 */	public void setRefreshTime(String time) {		mHeaderTimeView.setText(time);	}	private void invokeOnScrolling() {		if (mScrollListener instanceof OnXScrollListener) {			OnXScrollListener l = (OnXScrollListener) mScrollListener;			l.onXScrolling(this);		}	}	private void updateHeaderHeight(float delta) {		mHeaderView.setVisiableHeight((int) delta				+ mHeaderView.getVisiableHeight());		if (mEnablePullRefresh && !mPullRefreshing) { // 未处于刷新状态,更新箭头			if (mHeaderView.getVisiableHeight() > mHeaderViewHeight) {				mHeaderView.setState(XListViewHeader.STATE_READY);			} else {				mHeaderView.setState(XListViewHeader.STATE_NORMAL);			}			if (mPullLoading) { // disable, hide the content				mHeaderViewContent.setVisibility(View.INVISIBLE);			} else {				mHeaderViewContent.setVisibility(View.VISIBLE);			}		}		setSelection(0); // scroll to top each time	}	/**	 * reset header view's height.	 */	private void resetHeaderHeight() {		int height = mHeaderView.getVisiableHeight();		if (height == 0) // not visible.			return;		// refreshing and header isn't shown fully. do nothing.		if (mPullRefreshing && height <= mHeaderViewHeight) {			return;		}		int finalHeight = 0; // default: scroll back to dismiss header.		// is refreshing, just scroll back to show all the header.		if (mPullRefreshing && height > mHeaderViewHeight) {			finalHeight = mHeaderViewHeight;		}		mScrollBack = SCROLLBACK_HEADER;		mScroller.startScroll(0, height, 0, finalHeight - height,				SCROLL_DURATION);		// trigger computeScroll		invalidate();	}	/**	 * 触屏监听	 */	@Override	public boolean onTouchEvent(MotionEvent ev) {		if (mLastY == -1) {			mLastY = ev.getRawY();		}		switch (ev.getAction()) {		case MotionEvent.ACTION_DOWN:			mLastY = ev.getRawY();			break;		case MotionEvent.ACTION_MOVE:			final float deltaY = ev.getRawY() - mLastY;			// DLog.i(TAG, "deltaY is " + deltaY);			mLastY = ev.getRawY();			if (getFirstVisiblePosition() == 0					&& (mHeaderView.getVisiableHeight() > 0 || deltaY > 0)) {				// the first item is showing, header has shown or pull down.				updateHeaderHeight(deltaY / OFFSET_RADIO);				invokeOnScrolling();			} else if (getLastVisiblePosition() == mTotalItemCount - 1) {				// last item, already pulled up or want to pull up.			}			break;		default:			mLastY = -1; // reset			if (getFirstVisiblePosition() == 0) {				// invoke refresh				if (!mPullRefreshing && mEnablePullRefresh && !mPullLoading						&& mHeaderView.getVisiableHeight() > mHeaderViewHeight) {					mPullRefreshing = true;					mHeaderView.setState(XListViewHeader.STATE_REFRESHING);					// DLog.i(TAG, "invoke refresh");					if (mListViewListener != null) {						// 此时执行刷刷新的方法						mListViewListener.onRefresh();					}				}				resetHeaderHeight();			} else if (getLastVisiblePosition() == mTotalItemCount - 1) {				// invoke load more.				if (!mPullLoading && mEnablePullLoad && !mPullRefreshing) {					// DLog.i(TAG, "invoke load more");				}			}			break;		}		return super.onTouchEvent(ev);	}	@Override	public void computeScroll() {		if (mScroller.computeScrollOffset()) {			if (mScrollBack == SCROLLBACK_HEADER) {				mHeaderView.setVisiableHeight(mScroller.getCurrY());			} else {			}			postInvalidate();			invokeOnScrolling();		}		super.computeScroll();	}	@Override	public void setOnScrollListener(OnScrollListener l) {		mScrollListener = l;	}	/**	 * 在滚动时回调,回调2-3次,手指没抛开则回调2次,scrollState = 2的这次不回调 第1次:scrollState =	 * SCROLL_STATE_TOUCH_SCROLL(1) 正在滚动 第2次:scrollState =	 * SCROLL_STATE_FLING(2)手指做了抛的动作(手指离开屏幕前,用力滑了一下) 第3次:scrollState =	 * SCROLL_STATE_IDLE(0) 停止滚动	 */	@Override	public void onScrollStateChanged(AbsListView view, int scrollState) {		if (mScrollListener != null) {			mScrollListener.onScrollStateChanged(view, scrollState);		}		// 滑到底部时,自动加载更多。 也可以禁用此逻辑		if (getLastVisiblePosition() == mTotalItemCount - 1				&& scrollState == SCROLL_STATE_IDLE) {			if (!mPullLoading && mEnablePullLoad && !mPullRefreshing) {				// DLog.i(TAG, "invoke load more");			}		}	}	/**	 * 正在滚动的时候回调,停止滚动时才停止回调,单击时回调一次	 */	@Override	public void onScroll(AbsListView view, int firstVisibleItem,			int visibleItemCount, int totalItemCount) {		// send to user's listener		mTotalItemCount = totalItemCount;		if (mScrollListener != null) {			mScrollListener.onScroll(view, firstVisibleItem, visibleItemCount,					totalItemCount);		}	}	public void setXListViewListener(IXListViewListener l) {		mListViewListener = l;	}	/**	 * 监听ListView的滑动事件	 * 	 * @author cyf	 * 	 */	public interface OnXScrollListener extends OnScrollListener {		public void onXScrolling(View view);	}	/**	 * 自定义接口	 */	public interface IXListViewListener {		// 下拉刷新时候执行的方法		public void onRefresh();		// 上拉加载时候执行的方法		public void onLoadMore();	}}

 MainActivity的

package com.test.andy;import java.util.ArrayList;import com.test.andy.view.XListView;import com.test.andy.view.XListView.IXListViewListener;import com.test.andy.R;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.widget.ArrayAdapter;/** * XListViewActivity * 实现IXListViewListener接口是为了实现其中的下拉刷新等方法 * @author cyf * */public class XListViewActivity extends Activity implements IXListViewListener {	//自定义的ListView	private XListView mListView;	private ArrayAdapter<String> mAdapter;	private ArrayList<String> items = new ArrayList<String>();	private Handler mHandler;	private int start = 0;	private int refreshCnt = 0;	/** Called when the activity is first created. */	@Override	public void onCreate(Bundle savedInstanceState) {		super.onCreate(savedInstanceState);		setContentView(R.layout.main);		//初始化的时候加载20条数据		geneItems();		mListView = (XListView) findViewById(R.id.xListView);		mListView.setPullLoadEnable(true);		mAdapter = new ArrayAdapter<String>(this, R.layout.list_item, items);		mListView.setAdapter(mAdapter);//		mListView.setPullRefreshEnable(false);		mListView.setXListViewListener(this);		mHandler = new Handler();		mListView.startRefresh();	}	private void geneItems() {		for (int i = 0; i != 20; ++i) {			items.add("refresh cnt " + (++start));		}	}	private void onLoad() {		mListView.stopRefresh();		mListView.stopLoadMore();		mListView.setRefreshTime("刚刚");	}		@Override	public void onRefresh() {		mHandler.postDelayed(new Runnable() {			@Override			public void run() {				start = ++refreshCnt;				items.clear();				geneItems();				// mAdapter.notifyDataSetChanged();				mAdapter = new ArrayAdapter<String>(XListViewActivity.this, R.layout.list_item, items);				mListView.setAdapter(mAdapter);				onLoad();			}		}, 2000);	}	@Override	public void onLoadMore() {		mHandler.postDelayed(new Runnable() {			@Override			public void run() {				geneItems();				mAdapter.notifyDataSetChanged();				onLoad();			}		}, 2000);	}}

 重要的代码都总结在这了,希望给大家带来帮助,谢谢。