ViewDragHelper實現下拉刷新

前言

使用ViewDragHelper實現肯定可以實現下拉刷新,而且可以通過這種場景可以舉一反三出很多其他的場景。

實現步驟

1.首先看一下布局文件

<?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=".MainActivity" >

  <com.xsh.customviewstudy.view.PullToRefreshLayout
      android:id="@+id/refreshable_view"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >

      <include layout="@layout/pull_to_refresh" />

      <ListView
          android:id="@+id/list_view"
          android:layout_width="fill_parent"
          android:layout_height="fill_parent"
          android:scrollbars="none" >
      </ListView>
    </LinearLayout>
  </com.xsh.customviewstudy.view.PullToRefreshLayout>

</RelativeLayout>

PullToRefreshLayout是個ViewGroup,它下面有一個子類,這個子類下又包含兩個子類,一個就是head部分,一個就是ListView部分

2.接下來看PullToRefreshLayout的實現

import android.content.Context;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AbsListView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.xsh.customviewstudy.R;

public class PullToRefreshLayout extends LinearLayout {
    private final String TAG="PullToRefreshLayout";
    /**
     * 下拉狀態
     */
    public static final int STATUS_PULL_TO_REFRESH = 0;

    /**
     * 釋放立即刷新狀態
     */
    public static final int STATUS_RELEASE_TO_REFRESH = 1;

    /**
     * 正在刷新狀態
     */
    public static final int STATUS_REFRESHING = 2;

    /**
     * 刷新完成或未刷新狀態
     */
    public static final int STATUS_REFRESH_FINISHED = 3;
    

    /**
     * 下拉頭的View
     */
    private View header;

    /**
     * 刷新時顯示的進度條
     */
    private ProgressBar progressBar;

    /**
     * 指示下拉和釋放的文字描述
     */
    private TextView description;

    /**
     * 下拉頭的布局參數
     */
    private MarginLayoutParams headerLayoutParams;

    /**
     * 當前處理什么狀態,可選值有STATUS_PULL_TO_REFRESH, STATUS_RELEASE_TO_REFRESH,
     * STATUS_REFRESHING 和 STATUS_REFRESH_FINISHED
     */
    private int currentStatus = STATUS_REFRESH_FINISHED;;

    
    /**
     * 記錄上一次的狀態是什么,避免進行重復操作
     */
    private int lastStatus = currentStatus;

    /**
     * 用于處理事件分發的mDragger 
     */
    private ViewDragHelper mDragger;

    /**
     * 需要去下拉刷新的ListView
     */
    private AbsListView listView;
    
    private LinearLayout pullLayout;
    /**
     * 下拉頭的高度
     */
    private int hideHeaderHeight;
    
    /**
     * 當前滑動的距離 
     */
    private int currentTop;
    
    /**
     * 允許滑動的最大距
     */
    private int maxDragHeight;
    /**
     * 是否加載過
     */
    private boolean loadOnce=false;
    
    private boolean isTouch=false;
    
    private PullToRefreshListener pullToRefreshListener;
    
    public PullToRefreshLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        if(changed && !loadOnce){
            maxDragHeight=getMeasuredHeight()/2;
            hideHeaderHeight = -header.getHeight();
            headerLayoutParams = (MarginLayoutParams) pullLayout.getLayoutParams();
            headerLayoutParams.topMargin = hideHeaderHeight;
            loadOnce = true;
        }
    }
    
    @Override
    public void computeScroll() {
        super.computeScroll();
        if(mDragger.continueSettling(true)){
            invalidate();
        }
    }
    
    /**
     * 設置刷新回調接口
     * @param listener
     */
    public void setPullToRefreshistener(PullToRefreshListener listener){
        this.pullToRefreshListener=listener;
    }
    
    /**
     * 完成刷新
     */
    public void finishPullToRefresh(){
        currentStatus=STATUS_REFRESH_FINISHED;
        mDragger.smoothSlideViewTo(pullLayout, 0, hideHeaderHeight);
        invalidate();
    }
    
    /**
     * 初始化view 
     */
    private void init(){
        pullLayout=(LinearLayout) getChildAt(0);
        listView = (AbsListView) pullLayout.getChildAt(1);
        header = pullLayout.getChildAt(0);
        progressBar = (ProgressBar) header.findViewById(R.id.progress_bar);
        description = (TextView) header.findViewById(R.id.description);
        
        mDragger=ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {
            /**
             * 進行捕獲攔截,那些View可以進行drag操作
             * @param childView
             * @param position
             * @return  直接返回true,攔截所有的VIEW
             */
            @Override
            public boolean tryCaptureView(View childView, int position) {
                Log.i(TAG, "tryCaptureView");
                isTouch=true;
                return childView==pullLayout && isTop() ;
            }
            
            @Override
            public int clampViewPositionVertical(View child, int top, int dy) {
                Log.i(TAG, "clampViewPositionVertical: top="+top+"dy="+dy+"hideHeaderHeight="+hideHeaderHeight+"maxDragHeight="+maxDragHeight);
                if(top<=hideHeaderHeight){
                    return hideHeaderHeight;
                }else if(top>maxDragHeight){
                    return maxDragHeight;
                }
                return top;
            }
             @Override
            public void onViewReleased(View releasedChild, float xvel,  float yvel) {
                 Log.i(TAG, "onViewReleased");
                super.onViewReleased(releasedChild, xvel, yvel);
                if (releasedChild == pullLayout){
                    isTouch=false;
                    if (currentStatus == STATUS_RELEASE_TO_REFRESH ) {
                        // 松手時如果是釋放立即刷新狀態,就去調用正在刷新的任務
                        currentStatus = STATUS_REFRESHING;
                        updateHeadView();
                        mDragger.settleCapturedViewAt(0,0);
                        invalidate();
                        if(pullToRefreshListener!=null){
                            pullToRefreshListener.onRefresh();
                        }
                    }else if(currentStatus == STATUS_PULL_TO_REFRESH ){
                        mDragger.settleCapturedViewAt(0,hideHeaderHeight);
                        invalidate();
                    }else if(currentStatus == STATUS_REFRESHING){
                        mDragger.settleCapturedViewAt(0,0);
                        invalidate();
                    }

                }
            }
             
             @Override
            public void onViewPositionChanged(View changedView, int left,
                    int top, int dx, int dy) {
                super.onViewPositionChanged(changedView, left, top, dx, dy);
                Log.i(TAG, "onViewPositionChanged: top="+top);
                currentTop=top;
                if (isTouch && currentStatus != STATUS_REFRESHING){
                    if (currentTop <0) {
                        currentStatus = STATUS_PULL_TO_REFRESH;
                    } else {
                        currentStatus = STATUS_RELEASE_TO_REFRESH;
                    }
                    updateHeadView();
                    lastStatus=currentStatus;
                }
            }
             @Override
            public int getViewVerticalDragRange(View child) {
                 return maxDragHeight;
            }
            
        });
        
    }
    
    private void updateHeadView(){
        if(lastStatus!=currentStatus){
            if (currentStatus == STATUS_PULL_TO_REFRESH) {
                description.setText(getResources().getString(R.string.pull_to_refresh));
                progressBar.setVisibility(View.GONE);
            } else if (currentStatus == STATUS_RELEASE_TO_REFRESH) {
                description.setText(getResources().getString(R.string.release_to_refresh));
                progressBar.setVisibility(View.GONE);
            } else if (currentStatus == STATUS_REFRESHING) {
                description.setText(getResources().getString(R.string.refreshing));
                progressBar.setVisibility(View.VISIBLE);
            }
        }

    }
    private boolean isTop(){
        return listView.getFirstVisiblePosition() == 0
                && getScrollY() <= listView.getMeasuredHeight();
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return mDragger.shouldInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mDragger.processTouchEvent(event);
        return true;
    }
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        init();
    }
    
    public interface PullToRefreshListener {
        /**
         * 下拉刷新時調用
         */
        void onRefresh();
        
        /**
         * 上拉加載更多的刷新
         */
//      void onLoadMoreRefresh();

    }

}

1.protected void onFinishInflate() :實例化各個子View,比如LinearLayout,ListView,progressBar等等
實例化ViewDragHelper

2.protected void onLayout(boolean changed, int l, int t, int r, int b) : 把head隱藏起來

3.其他部分就沒什么好的,so easy

源碼參考我的github地址

參考文章

http://blog.csdn.net/liuwang521/article/details/52764520

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容