相信大家都已经见过人人、QQ、新浪微博等客户端的下拉刷新功能,感觉用起来是不是特别爽,现在我就从网上copy了一段代码过来和大家一起学习学习。先把代码贴出来,等你们在自己机子上运行了先。
新建项目:com.markupartist.android.example.pulltorefresh,Activity名为:PullToRefreshActivity
再建立一个包:com.markupartist.android.widget,里面建一个文件:PullToRefreshListView
XML文件,文件名:pull_to_refresh.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <!-- 此处是自定义ListView控件 --> <com.markupartist.android.widget.PullToRefreshListView android:id="@+id/usalist" android:layout_height="fill_parent" android:layout_width="fill_parent" > </com.markupartist.android.widget.PullToRefreshListView> </LinearLayout>
[代码]文件名:pull_to_refresh_header.xml:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:paddingTop="10dip" android:paddingBottom="15dip" android:gravity="center" android:id="@+id/pull_to_refresh_header" > <ProgressBar android:id="@+id/pull_to_refresh_progress" android:indeterminate="true" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="30dip" android:layout_marginRight="20dip" android:layout_marginTop="10dip" android:visibility="gone" android:layout_centerVertical="true" style="@drawable/icon" /> <ImageView android:id="@+id/pull_to_refresh_image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="30dip" android:layout_marginRight="20dip" android:visibility="gone" android:layout_gravity="center" android:gravity="center" android:src="@drawable/goicon" /> <TextView android:id="@+id/pull_to_refresh_text" android:text="@string/pull_to_refresh_tap_label" android:textAppearance="?android:attr/textAppearanceMedium" android:textStyle="bold" android:paddingTop="5dip" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:gravity="center" /> <TextView android:id="@+id/pull_to_refresh_updated_at" android:layout_below="@+id/pull_to_refresh_text" android:visibility="gone" android:textAppearance="?android:attr/textAppearanceSmall" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:gravity="center" /> </RelativeLayout>
[代码]PullToRefreshActivity.java:
package com.markupartist.android.example.pulltorefresh; import java.util.Arrays; import java.util.LinkedList; import android.app.Activity; import android.app.ListActivity; import android.os.AsyncTask; import android.os.Bundle; import android.widget.ArrayAdapter; import com.markupartist.android.widget.PullToRefreshListView; import com.markupartist.android.widget.PullToRefreshListView.OnRefreshListener; public class PullToRefreshActivity extends Activity { private LinkedList<String> mListItems; //此处开始初始化mlistview,包括一些事件 private PullToRefreshListView mlistview; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.pull_to_refresh); // Set a listener to be invoked when the list should be refreshed. mlistview = ((PullToRefreshListView)PullToRefreshActivity.this.findViewById(R.id.usalist) ); mlistview.setOnRefreshListener(new OnRefreshListener() { @Override public void onRefresh() { // TODO Auto-generated method stub new GetDataTask().execute(); } });/*() { @Override public void onRefresh() { // Do work to refresh the list here. new GetDataTask().execute(); } });*/ mListItems = new LinkedList<String>(); mListItems.addAll(Arrays.asList(mStrings)); ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mListItems); mlistview.setAdapter(adapter); } //执行异步的操作 private class GetDataTask extends AsyncTask<Void, Void, String[]> { @Override protected String[] doInBackground(Void... params) { // Simulates a background job. try { Thread.sleep(2000); } catch (InterruptedException e) { ; } return mStrings; } @Override protected void onPostExecute(String[] result) { mListItems.addFirst("Added after refresh..."); // Call onRefreshComplete when the list has been refreshed. mlistview.onRefreshComplete(); super.onPostExecute(result); } } private String[] mStrings = { "Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi", "Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu", "Airag", "Airedale", "Aisy Cendre", "Allgauer Emmentaler"}; }
[代码]PullToRefreshListView.java:
package com.markupartist.android.widget; import com.markupartist.android.example.pulltorefresh.R; 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.LinearInterpolator; import android.view.animation.RotateAnimation; import android.widget.AbsListView; import android.widget.ImageView; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.AbsListView.OnScrollListener; public class PullToRefreshListView extends ListView implements OnScrollListener { /**初始状态*/ private static final int TAP_TO_REFRESH = 1; /**拉动刷新*/ private static final int PULL_TO_REFRESH = 2; /**释放刷新**/ private static final int RELEASE_TO_REFRESH = 3; /**正在刷新*/ private static final int REFRESHING = 4; private static final String TAG = "PullToRefreshListView"; //刷新接口 private OnRefreshListener mOnRefreshListener; //箭头图片 private static int REFRESHICON = R.drawable.goicon; /** * listview 滚动监听器 */ private OnScrollListener mOnScrollListener; //视图索引器 private LayoutInflater mInflater; /** * 头部视图 内容 -- start */ private RelativeLayout mRefreshView; private TextView mRefreshViewText; private ImageView mRefreshViewImage; private ProgressBar mRefreshViewProgress; private TextView mRefreshViewLastUpdated; /** * 头部视图 内容 -- end */ /**当前listivew 的滚动状态*/ private int mCurrentScrollState; /**当前listview 的刷新状态*/ private int mRefreshState; //动画效果 /**变为向下的箭头*/ private RotateAnimation mFlipAnimation; /**变为逆向的箭头*/ private RotateAnimation mReverseFlipAnimation; //头视图的高度 private int mRefreshViewHeight; //头视图 原始的 top padding 属性值 private int mRefreshOriginalTopPadding; // private int mLastMotionY; //是否反弹 private boolean mBounceHack; public PullToRefreshListView(Context context) { super(context); init(context); } public PullToRefreshListView(Context context, AttributeSet attrs) { super(context, attrs); //默认此处构造函数 init(context); } public PullToRefreshListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } private void init(Context context) { // Load all of the animations we need in code rather than through XML //初始化动画 // mFlipAnimation = new RotateAnimation(0, -180,RotateAnimation.RELATIVE_TO_SELF, 0.5f,RotateAnimation.RELATIVE_TO_SELF, 0.5f); mFlipAnimation.setInterpolator(new LinearInterpolator());//设置速度模式为LinearInterpolator mFlipAnimation.setDuration(250);//设置持续时间 mFlipAnimation.setFillAfter(true);//设置为填充状态 mReverseFlipAnimation = new RotateAnimation(-180, 0,RotateAnimation.RELATIVE_TO_SELF, 0.5f,RotateAnimation.RELATIVE_TO_SELF, 0.5f); mReverseFlipAnimation.setInterpolator(new LinearInterpolator()); mReverseFlipAnimation.setDuration(250); mReverseFlipAnimation.setFillAfter(true); mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);//设置minflater为获取XML文件格式 mRefreshView = (RelativeLayout) mInflater.inflate(R.layout.pull_to_refresh_header, this, false);//(R.layout.pull_to_refresh_header, null); mRefreshViewText =(TextView) mRefreshView.findViewById(R.id.pull_to_refresh_text); mRefreshViewImage =(ImageView) mRefreshView.findViewById(R.id.pull_to_refresh_image); mRefreshViewProgress = (ProgressBar) mRefreshView.findViewById(R.id.pull_to_refresh_progress); mRefreshViewLastUpdated = (TextView) mRefreshView.findViewById(R.id.pull_to_refresh_updated_at); mRefreshViewImage.setMinimumHeight(50); //mRefreshView.setOnClickListener(new OnClickRefreshListener());//此处毫无用处,不会调用此代码 mRefreshOriginalTopPadding = mRefreshView.getPaddingTop(); System.out.println("设置为初始状态"); mRefreshState = TAP_TO_REFRESH;//初始状态 addHeaderView(mRefreshView);//将mRefreshView加入ListView头部 super.setOnScrollListener(this); measureView(mRefreshView); mRefreshViewHeight = mRefreshView.getMeasuredHeight(); //获取头文件的测量高度 } @Override protected void onAttachedToWindow() { setSelection(1); } @Override public void setAdapter(ListAdapter adapter) { super.setAdapter(adapter); setSelection(1); } /** * Set the listener that will receive notifications every time the list * scrolls. * * @param l The scroll listener. */ @Override public void setOnScrollListener(AbsListView.OnScrollListener l) { System.out.println("时刻刷新"); mOnScrollListener = l; } /** * Register a callback to be invoked when this list should be refreshed. * * @param onRefreshListener The callback to run. */ public void setOnRefreshListener(OnRefreshListener onRefreshListener) { mOnRefreshListener = onRefreshListener; } /** * Set a text to represent when the list was last updated. * @param lastUpdated Last updated at. */ public void setLastUpdated(CharSequence lastUpdated) { if (lastUpdated != null) { mRefreshViewLastUpdated.setVisibility(View.VISIBLE); mRefreshViewLastUpdated.setText(lastUpdated); } else { mRefreshViewLastUpdated.setVisibility(View.GONE); } } @Override public boolean onTouchEvent(MotionEvent event) { //当前手指的Y值 final int y = (int) event.getY(); //Log.i(TAG, "触屏的Y值"+y); mBounceHack = false; //不反弹 switch (event.getAction()) { case MotionEvent.ACTION_UP: //将垂直滚动条设置为可用状态 if (!isVerticalScrollBarEnabled()) { setVerticalScrollBarEnabled(true); } //如果头部刷新条出现,并且不是正在刷新状态 if (getFirstVisiblePosition() == 0 && mRefreshState != REFRESHING) { if ((mRefreshView.getBottom() >= mRefreshViewHeight || mRefreshView.getTop() >= 0) && mRefreshState == RELEASE_TO_REFRESH) { //如果头部视图处于拉离顶部的情况 // Initiate the refresh mRefreshState = REFRESHING; //将标量设置为,正在刷新 prepareForRefresh(); //准备刷新 onRefresh(); //刷新 } else if (mRefreshView.getBottom() < mRefreshViewHeight || mRefreshView.getTop() <= 0) { // Abort refresh and scroll down below the refresh view // 停止刷新,并且滚动到头部刷新视图的下一个视图 resetHeader(); setSelection(1); //定位在第二个列表项 } } break; case MotionEvent.ACTION_DOWN: mLastMotionY = y; //跟踪手指的Y值 break; case MotionEvent.ACTION_MOVE: //更行头视图的toppadding 属性 applyHeaderPadding(event); break; } return super.onTouchEvent(event); } /**** * 不断的头部的top padding 属性 * @param ev */ private void applyHeaderPadding(MotionEvent ev) { //获取累积的动作数 int pointerCount = ev.getHistorySize(); // Log.i(TAG, "获取累积的动作数"+pointerCount); for (int p = 0; p < pointerCount; p++) { if (mRefreshState == RELEASE_TO_REFRESH) { //如果是释放将要刷新状态 if (isVerticalFadingEdgeEnabled()) { setVerticalScrollBarEnabled(false); } //历史累积的高度 int historicalY = (int) ev.getHistoricalY(p); //Log.i(TAG, "单个动作getHistoricalY值:"+historicalY); // Calculate the padding to apply, we divide by 1.7 to // simulate a more resistant effect during pull. int topPadding = (int) (((historicalY - mLastMotionY) - mRefreshViewHeight) / 1.7); mRefreshView.setPadding( mRefreshView.getPaddingLeft(), topPadding, mRefreshView.getPaddingRight(), mRefreshView.getPaddingBottom()); } } } /** * Sets the header padding back to original size. * 使头部视图的 toppadding 恢复到初始值 */ private void resetHeaderPadding() { mRefreshView.setPadding( mRefreshView.getPaddingLeft(), mRefreshOriginalTopPadding, mRefreshView.getPaddingRight(), mRefreshView.getPaddingBottom()); } /** * Resets the header to the original state. * 初始化头部视图 状态 */ private void resetHeader() { if (mRefreshState != TAP_TO_REFRESH) { mRefreshState = TAP_TO_REFRESH; //初始刷新状态 //使头部视图的 toppadding 恢复到初始值 resetHeaderPadding(); // Set refresh view text to the pull label //将文字初始化 mRefreshViewText.setText(R.string.pull_to_refresh_tap_label); // Replace refresh drawable with arrow drawable //设置初始图片 mRefreshViewImage.setImageResource(REFRESHICON); // Clear the full rotation animation // 清除动画 mRefreshViewImage.clearAnimation(); // Hide progress bar and arrow. //隐藏头视图 mRefreshViewImage.setVisibility(View.GONE); //隐藏进度条 mRefreshViewProgress.setVisibility(View.GONE); } } //测量视图的高度 private void measureView(View child) { //获取头部视图属性 ViewGroup.LayoutParams p = child.getLayoutParams(); if (p == null) { p = new ViewGroup.LayoutParams( ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); } int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width); int lpHeight = p.height; int childHeightSpec; //不懂MeasureSpec------------------------------------------------------------------------------------------ if (lpHeight > 0) { //如果视图的高度大于0 childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY); } else { childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); } child.measure(childWidthSpec, childHeightSpec); //不懂MeasureSpec------------------------------------------------------------------------------------------ } /** * 滑动监听事件 */ @Override public void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) { // When the refresh view is completely visible, change the text to say // "Release to refresh..." and flip the arrow drawable. //System.out.println("是这个this?"); if (mCurrentScrollState == SCROLL_STATE_TOUCH_SCROLL //如果是接触滚动状态,并且不是正在刷新的状态 && mRefreshState != REFRESHING) { if (firstVisibleItem == 0) { //如果显示出来了第一个列表项 //显示刷新图片 mRefreshViewImage.setVisibility(View.VISIBLE); if ((mRefreshView.getBottom() >= mRefreshViewHeight + 20 || mRefreshView.getTop() >= 0) && mRefreshState != RELEASE_TO_REFRESH) { //如果下拉了listiview,则显示上拉刷新动画 mRefreshViewText.setText(R.string.pull_to_refresh_release_label); mRefreshViewImage.clearAnimation(); mRefreshViewImage.startAnimation(mFlipAnimation); mRefreshState = RELEASE_TO_REFRESH; Log.i(TAG, "现在处于下拉状态"); } else if (mRefreshView.getBottom() < mRefreshViewHeight + 20 && mRefreshState != PULL_TO_REFRESH) { //如果没有到达,下拉刷新距离,则回归原来的状态 mRefreshViewText.setText(R.string.pull_to_refresh_pull_label); if (mRefreshState != TAP_TO_REFRESH) { mRefreshViewImage.clearAnimation(); mRefreshViewImage.startAnimation(mReverseFlipAnimation); mRefreshViewText.setText("非刷新状态,开始回弹"); Log.i(TAG, "现在处于回弹状态"); } mRefreshState = PULL_TO_REFRESH; } } else { System.out.println("隐藏刷新图片"); mRefreshViewImage.setVisibility(View.GONE); //隐藏刷新图片 resetHeader(); //初始化,头部 } } else if (mCurrentScrollState == SCROLL_STATE_FLING //如果是自己滚动状态+ 第一个视图已经显示 + 不是刷新状态 && firstVisibleItem == 0 && mRefreshState != REFRESHING) { setSelection(1); mBounceHack = true; //状态为回弹 Log.i(TAG, "现在处于自由滚动到顶部的状态"); } else if (mBounceHack && mCurrentScrollState == SCROLL_STATE_FLING) { setSelection(1); Log.i(TAG, "现在处于自由滚动到顶部的状态"); } if (mOnScrollListener != null) { mOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount); } } //滚动状态改变 @Override public void onScrollStateChanged(AbsListView view, int scrollState) { mCurrentScrollState = scrollState; if (mCurrentScrollState == SCROLL_STATE_IDLE) { //如果滚动停顿 mBounceHack = false; } if (mOnScrollListener != null) { mOnScrollListener.onScrollStateChanged(view, scrollState); } } //准备刷新 public void prepareForRefresh() { resetHeaderPadding(); //初始化,头部文件 mRefreshViewImage.setVisibility(View.GONE); // We need this hack, otherwise it will keep the previous drawable. mRefreshViewImage.setImageDrawable(null); mRefreshViewProgress.setVisibility(View.VISIBLE); // Set refresh view text to the refreshing label mRefreshViewText.setText(R.string.pull_to_refresh_refreshing_label); mRefreshState = REFRESHING; } //刷新 public void onRefresh() { Log.d(TAG, "执行刷新"); if (mOnRefreshListener != null) { mOnRefreshListener.onRefresh(); } } /** * 刷新完成 的回调函数 * Resets the list to a normal state after a refresh. * @param lastUpdated Last updated at. */ public void onRefreshComplete(CharSequence lastUpdated) { setLastUpdated(lastUpdated); onRefreshComplete(); } /** * 刷新完成回调函数 * Resets the list to a normal state after a refresh. */ public void onRefreshComplete() { Log.d(TAG, "onRefreshComplete"); resetHeader(); // If refresh view is visible when loading completes, scroll down to // the next item. if (mRefreshView.getBottom() > 0) { invalidateViews(); //重绘视图 setSelection(1); } } /** * Invoked when the refresh view is clicked on. This is mainly used when * there's only a few items in the list and it's not possible to drag the * list. */ private class OnClickRefreshListener implements OnClickListener { @Override public void onClick(View v) { if (mRefreshState != REFRESHING) { //准备刷新 System.out.println("准备刷新"); prepareForRefresh(); System.out.println("开始刷新"); //刷新 onRefresh(); } } } /** * 刷新方法接口 */ public interface OnRefreshListener { public void onRefresh(); } }