1. 程式人生 > >Android自定義上拉載入下拉重新整理PullToRefreshListView

Android自定義上拉載入下拉重新整理PullToRefreshListView

  轉自http://blog.csdn.net/allen315410/article/details/39965327
  最近專案中要用到重新整理和載入的功能,網上查了有好多關於重新整理和載入的例子,挑了一個比較好的,有些地方更完善了些。例如下拉不完全時沒有做處理,還有載入後滑動有些問題都一一解決了。話不多說,先看效果圖,後直接上程式碼了。
  這裡寫圖片描述
  這裡寫圖片描述
  這裡寫圖片描述
  這裡寫圖片描述
 RefreshListView:

public class RefreshListView extends ListView implements AbsListView.OnScrollListener {

    private
final static String TAG = "RefreshListView"; private View mHeaderView;//頭佈局物件 private ImageView mImageViewArror;//頭佈局的箭頭 private ProgressBar mProgressBar;//進度條 private TextView mTextViewState;//頭佈局的狀態 private TextView mTextViewTime;//頭佈局的時間 private int mHeaderViewHeight;//mHeaderView的高度
private Animation mUpAnimation;//頂部的動畫 private Animation mDownAnimation;//底部的動畫 private View mFooterView;//腳佈局物件 private int mFooterViewHeight;//mFooterView的高度 private boolean mIsScrollToBottom;//是否滑動到底部 private boolean mIsLoadingMore = false;//是否正在載入更多中 private OnRefreshListener mOnRefreshListener; private
int mDownY;//按下時y軸的偏移量 private final static int DOWM_PULL_REFRESH = 0;//下拉重新整理狀態 private final static int RELEASE_REFRESH = 1;//鬆開重新整理 private final static int REFRESHING = 2;//正在重新整理 private int currentState = DOWM_PULL_REFRESH;//當前佈局的狀態,預設為下拉重新整理狀態 private int mFirstVisibleItemPosition;//螢幕顯示在第一個的item的索引 public RefreshListView(Context context) { this(context, null); } public RefreshListView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public RefreshListView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initHeaderView(); initFooterView(); this.setOnScrollListener(this); } /** * 初始化頭佈局 */ private void initHeaderView() { mHeaderView = View.inflate(getContext(), R.layout.header, null); mImageViewArror = (ImageView) mHeaderView.findViewById(R.id.iv_header); mProgressBar = (ProgressBar) mHeaderView.findViewById(R.id.progressBar); mTextViewState = (TextView) mHeaderView.findViewById(R.id.tv_header_state); mTextViewTime = (TextView) mHeaderView.findViewById(R.id.tv_header_time); //設定最後的重新整理時間 mTextViewTime.setText("最後重新整理時間:" + getLastUpdateTime()); mHeaderView.measure(0, 0);//系統會幫我們測量出mHeaderView的高度 mHeaderViewHeight = mHeaderView.getMeasuredHeight(); mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0); this.addHeaderView(mHeaderView);//向ListView的頂部新增一個View物件 initAnimation(); } /** * 獲取系統最新時間 * * @return */ @TargetApi(Build.VERSION_CODES.N) private String getLastUpdateTime() { SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss"); return format.format(System.currentTimeMillis()); } /** * 初始化動畫 */ private void initAnimation() { mUpAnimation = new RotateAnimation(0f, -180f, Animation.RELATIVE_TO_SELF, 0.5f, Animation .RELATIVE_TO_SELF, 0.5f); mUpAnimation.setDuration(500); mUpAnimation.setFillAfter(true);//動畫結束後,停留在結束的位置上 mDownAnimation = new RotateAnimation(-180f, -360f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); mDownAnimation.setDuration(500); mDownAnimation.setFillAfter(true); } /** * 初始化腳佈局 */ private void initFooterView() { mFooterView = View.inflate(getContext(), R.layout.loading, null); mFooterView.measure(0, 0); mFooterViewHeight = mFooterView.getMeasuredHeight(); mFooterView.setPadding(0, -mFooterViewHeight, 0, 0); this.addFooterView(mFooterView); } /** * 當滾動狀態改變時回撥 */ @Override public void onScrollStateChanged(AbsListView absListView, int scrollState) { if (scrollState == SCROLL_STATE_IDLE || scrollState == SCROLL_STATE_FLING) { //判斷當前是否已經載入到了底部 if (mIsScrollToBottom && !mIsLoadingMore) { mIsLoadingMore = true; //當前到底部 Log.i(TAG, "載入更多資料"); mFooterView.setPadding(0, 0, 0, 0); this.setSelection(this.getCount()); if (mOnRefreshListener != null) { mOnRefreshListener.onLoadingMore(); } } } } /** * 當滾動時呼叫 * * @param firstVisibleItem 當前螢幕顯示在頂部的item的position * @param visibleItemCount 當前螢幕顯示了多少個條目的總數 * @param totalItemCount ListView的總條目數 */ @Override public void onScroll(AbsListView absListView, int firstVisibleItem, int visibleItemCount, int totalItemCount) { mFirstVisibleItemPosition = firstVisibleItem; if (getLastVisiblePosition() == (totalItemCount - 1) && !mIsLoadingMore) { mIsScrollToBottom = true; } else { mIsScrollToBottom = false; } } public interface OnRefreshListener { /** * 下拉重新整理 */ void onDownPullToRefresh(); /** * 上拉載入更多 */ void onLoadingMore(); } /** * 設定重新整理監聽事件 */ public void setmOnRefreshListener(OnRefreshListener listener) { this.mOnRefreshListener = listener; } @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: mDownY = (int) ev.getY(); break; case MotionEvent.ACTION_MOVE: int moveY = (int) ev.getY(); //移動後的y-按下的y = 間距 int distanceY = (moveY - mDownY) / 2; //-頭佈局的高度+間距=paddingTop int paddingTop = -mHeaderViewHeight + distanceY; //如果:- 頭佈局的高度>paddingTop的值,執行super.onTouchEvent(ev); if (mFirstVisibleItemPosition == 0 && -mHeaderViewHeight < paddingTop) { if (paddingTop > 0 && currentState == DOWM_PULL_REFRESH) {//完全顯示了 Log.i(TAG, "鬆開重新整理"); currentState = RELEASE_REFRESH; refreshHeaderView(); } else if (paddingTop < 0 && currentState == RELEASE_REFRESH) { Log.i(TAG, "下拉重新整理"); currentState = DOWM_PULL_REFRESH; refreshHeaderView(); } //下拉頭佈局 mHeaderView.setPadding(0, paddingTop, 0, 0); return true; } break; case MotionEvent.ACTION_UP: //判斷當前狀態是鬆開重新整理還是下拉重新整理 switch (currentState) { case RELEASE_REFRESH: Log.i(TAG, "重新整理資料"); //把頭佈局設定為完全顯示狀態 mHeaderView.setPadding(0, 0, 0, 0); //進入到正在重新整理中狀態 currentState = REFRESHING; refreshHeaderView(); if (mOnRefreshListener != null) { mOnRefreshListener.onDownPullToRefresh();//呼叫使用者的監聽方法 } } break; case DOWM_PULL_REFRESH: //隱藏頭佈局 mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0); break; } break; default: break; } return super.onTouchEvent(ev); } /** * 根據currentState重新整理頭佈局 */ private void refreshHeaderView() { switch (currentState) { case DOWM_PULL_REFRESH://下拉重新整理 mTextViewState.setText("下拉重新整理"); mImageViewArror.startAnimation(mDownAnimation); break; case RELEASE_REFRESH://鬆開重新整理 mTextViewState.setText("鬆開重新整理"); mImageViewArror.startAnimation(mUpAnimation); break; case REFRESHING://正在重新整理 mImageViewArror.clearAnimation(); mImageViewArror.setVisibility(View.GONE); mProgressBar.setVisibility(View.VISIBLE); mTextViewState.setText("正在重新整理中..."); break; } } /** * 隱藏頭佈局 */ public void hideHeaderView() { mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0); mImageViewArror.setVisibility(View.VISIBLE); mProgressBar.setVisibility(View.GONE); mTextViewState.setText("下拉重新整理"); mTextViewTime.setText("最後重新整理時間:" + getLastUpdateTime()); currentState = DOWM_PULL_REFRESH; } public void hideFooterView() { mFooterView.setPadding(0, -mFooterViewHeight, 0, 0); mIsLoadingMore = false; } }

MainActivity:

public class MainActivity extends AppCompatActivity implements RefreshListView.OnRefreshListener {

    private RefreshListView mRefreshListView;
    private List<String> mData;
    private MyAdapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mRefreshListView = (RefreshListView) findViewById(R.id.refresh_listview);
        mData = new ArrayList<>();
        for(int i = 0;i < 25 ; i++){
            mData.add(i,"這是一條listview的資料"+i);
        }
        mAdapter = new MyAdapter(mData,this);
        mRefreshListView.setAdapter(mAdapter);
        mRefreshListView.setmOnRefreshListener(this);
    }

    @Override
    public void onDownPullToRefresh() {
        new AsyncTask<Void,Void,Void>(){

            @Override
            protected Void doInBackground(Void... voids) {
                try {
                    Thread.sleep(2000);
                    for (int i = 0; i < 2;i++) {
                        mData.add(0,"這是下拉刷新出來的資料"+i);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return null;
            }

            @Override
            protected void onPostExecute(Void aVoid) {
                mAdapter.notifyDataSetChanged();
                mRefreshListView.hideHeaderView();
            }
        }.execute(new Void[]{});
    }

    @Override
    public void onLoadingMore() {
        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... voids) {
                try {
                    Thread.sleep(3000);
                    mData.add("這是載入的資料1");
                    mData.add("這是載入的資料2");
                    mData.add("這是載入的資料3");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return null;
            }

            @Override
            protected void onPostExecute(Void aVoid) {
                mAdapter.notifyDataSetChanged();
                //隱藏腳佈局
                mRefreshListView.hideFooterView();
            }
        }.execute(new Void[]{});
    }
}

MyAdapter:

public class MyAdapter extends BaseAdapter{

    private List<String> mData;
    private Context mContext;
    private LayoutInflater mInflater;

    public MyAdapter(List<String> mData, Context mContext) {
        if(mData == null){
            this.mData = mData;
        }
        this.mData = mData;
        this.mContext = mContext;
        mInflater = LayoutInflater.from(mContext);
    }

    @Override
    public int getCount() {
        return mData.size();
    }

    @Override
    public Object getItem(int i) {
        return mData.get(i);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public View getView(int i, View convertView, ViewGroup viewGroup) {
        ViewHolder holder;
        if(convertView == null){
            convertView = mInflater.inflate(R.layout.listview_item,viewGroup,false);
            holder = new ViewHolder();
            convertView.setTag(holder);
            holder.tvItem = (TextView) convertView.findViewById(R.id.tv_item);
        }else{
            holder = (ViewHolder) convertView.getTag();
        }
        holder.tvItem.setText(mData.get(i));
        return convertView;
    }

    private class ViewHolder {
        private TextView tvItem;
    }
}

activity_main的佈局:

<?xml version="1.0" encoding="utf-8"?>
<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.ihavau.www.pulltorefreshlistviewdemo.MainActivity">

        <com.ihavau.www.pulltorefreshlistviewdemo.widget.RefreshListView
            android:id="@+id/refresh_listview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

</RelativeLayout>

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="horizontal">

    <FrameLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp">

        <ImageView
            android:id="@+id/iv_header"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:minHeight="30dp"
            android:src="@drawable/ptr_pulltorefresh_arrow"/>

        <ProgressBar
            android:id="@+id/progressBar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:indeterminateDrawable="@anim/common_progressbar"
            android:visibility="gone"/>
    </FrameLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:gravity="center_horizontal"
        android:orientation="vertical">

        <TextView
            android:id="@+id/tv_header_state"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="下拉重新整理"
            android:textColor="#FF0000"
            android:textSize="18sp"/>

        <TextView
            android:id="@+id/tv_header_time"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            android:text="最後重新整理時間:2016-6-7 17:47:30"/>
    </LinearLayout>
</LinearLayout>

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="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_margin="10dp"
        android:gravity="center"
        android:orientation="horizontal">

        <ProgressBar
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:indeterminateDrawable="@anim/common_progressbar"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="載入更多..."
            android:textColor="#FF0000"
            android:textSize="18sp"/>
    </LinearLayout>
</LinearLayout>

listview_item.xml的佈局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <TextView
        android:id="@+id/tv_item"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="20dp"
        android:textSize="18sp"/>

</LinearLayout>

程式碼下載地址:http://download.csdn.net/detail/zuozuoshenghen/9593649