Android自定義之ScrollView下拉刷新


公司項目,需要用到ScrollView的下拉刷新,一開始使用的時候PullToRefresh三方庫的下拉刷新,我比較糾結第三檔庫,很強大,但是,公司項目的需求,PullToRefresh就不能做到了,改來改去的還是自己寫一個下拉刷新比較靠譜,很多東西能夠自己去控制。效果圖就不上傳了。直接解釋關鍵代碼。
ScrollView的下拉刷新比ListView的好做多了。
因為ScroTo的性質,ScrollView的下拉刷新,需要在外部添加一個父布局,通過父布局來控制觸摸手勢時候下傳,什么時候下拉。
我自定義了一個PullScrollView 
public class PullScrollView extends RelativeLayout   

public PullScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }
    
    public PullScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }
    
    public PullScrollView(Context context) {
        super(context);
        init(context);
    }
    
    private Scroller mScroller ;
    private int mTouchSlop ;
    private void init(Context context){
        
         ViewConfiguration configuration = ViewConfiguration.get(getContext());
         mTouchSlop = configuration.getScaledTouchSlop();
        mScroller = new Scroller(context, new DecelerateInterpolator());
    }  

首先是初始化 mTouchSlop   是觸摸手勢滑動的最小像素值,也就是說滑動多少的距離才算是手勢滑動,這樣可以防止手勢一點點的移動就引起的滑動事件。
mScroller   是用來處理平滑滾動的。之前的博客有介紹。

第二點:
@Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        if (getChildCount() > 2) {
            throw new RuntimeException("子孩子只能有兩個");
        }
        bottomView = (ViewGroup) getChildAt(0);
        contentView = (ScrollView) getChildAt(1);
    }  

在布局初始化結束之后,得到布局中的兩個子孩子,為啥只能有兩個孩子那?? BottomView是用來下拉刷新展示的View  contentView 就是我們的ScrollView了。如果子孩子多了,怎么知道哪個VIew是需要被隱藏的?所以只處理兩個View的情況,當然,如果還有上拉加載更多,就需要三個子孩子了。


第三:

@Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        bottomHeight = getBottomViewHeight() ; 
        Log.i("Test", l + "ceshi" + " t="+t + " r"+r + " b=" + b + " height= "   + bottomHeight);
        bottomView.layout(l, - bottomHeight, r, t);
        contentView.layout(l, 0, r, b);
    }  
onLayout,做過自定義的都應該很熟悉這個方法,放置子孩子位置的一個方法,因為我們需要有一個子孩子隱藏掉,當我們需要它顯示的時候才去顯示,所以  需要手動的去將BottomView放到布局-hight到0的位置,這樣下拉的時候才能顯示出來。

第四:
@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        
        if (getScrollY() < 0 ) {
            return true ;
        }
        
        switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            startY = (int) ev.getY();
            break;
        case MotionEvent.ACTION_MOVE:
            int moveY = (int) ev.getY();
            int delayY = moveY - startY ;
            Log.i("Test", delayY + " =  " + mTouchSlop) ;
            if (getTopPosition() && delayY > mTouchSlop) {
                ev.setAction(MotionEvent.ACTION_DOWN);
                return true ;
            }
            break ;
        case MotionEvent.ACTION_UP:
            
            break;
        }
        return super.onInterceptTouchEvent(ev);
    }  

手勢的攔截動作,通過 getTopPosition()方式,來判斷ScrollView時候處於下拉需要顯示隱藏子View的狀態, delayY >  mTouchSlop 是用來判斷是不是下拉的動作的。 如果符合條件  我們就需要將手勢攔截掉,return true。
為什么我覺得ScrollView做下來刷新比較好做那? 就是因為ScrollView的判斷比較好判斷。

private boolean getTopPosition(){
        if (contentView.getScrollY() <= 0 ) {
            return true ;
        }
        return false ;
    }
是不是很簡單!!!!

第五:
@Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            startY = (int) event.getY();
            break;
        case MotionEvent.ACTION_MOVE:
            int delayY = (int) (event.getY() - startY) ;
            if (getTopPosition() && getScrollY() <= 0 ) {
                pullMove((int) (-delayY * 0.8));  // 跟隨手勢滑動
            }
            startY = (int) event.getY();
            return true ;
        case MotionEvent.ACTION_UP:
            int scrollY = getScrollY();
            if (state == PullState.ON_REFRESH && scrollY < 0 && Math.abs(scrollY) > bottomHeight) {
                restView(-getScrollY() - bottomHeight);  // 回彈到下拉刷新的狀態
                return true ;
            }else if (state == PullState.ON_REFRESH && scrollY < 0 && Math.abs(scrollY) < bottomHeight) {
                return true ;
            }
            if (scrollY < 0  &&  Math.abs(scrollY) < bottomHeight ) {
                returnView(); // 回彈到原來的位置。
            }else if (scrollY < 0 && Math.abs(scrollY) > bottomHeight  && state != PullState.ON_REFRESH) {
                if (onreListener != null) {
                    state = PullState.ON_REFRESH ;
                    onreListener.refresh();  // 回調函數
                }
                restView(-getScrollY() - bottomHeight);
            }
            break;
        }
        return true ;
    }  
這個就是做移動的處理手勢的方法了。

ScrollView的下拉刷新比起Listview ,要好做的多了。哈哈………………  
下面是源碼附上,用做學習之用。代碼還有不完善之處,等我項目完成之后,我會把項目中的封裝很完善的下拉刷新代碼重新打包上傳。

下載地址:   http://pan.baidu.com/s/1jG67mzc 








免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM