超简洁的下拉刷新(二)用srcoller实现

上一篇里面已经给大家介绍了用margin实现的下拉刷新,这篇介绍用scroller实现的,这也是目前我自己正在用的,体验要比magin流畅一点,为了写这个东西,特地去了解了一下scroller的用法,这里我就不过多介绍了,先上效果图:
超简洁的下拉刷新(二)用srcoller实现_第1张图片

接下来是主要代码:
MyFreshLayoutScroller.java

package com.example.freshscroller;
import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ScrollView;
import android.widget.Scroller;

public class MyFreshLayoutScroller extends LinearLayout {
private int mTouchSlop;
private LinearLayout headView;
private float yDown, iyDown,xDown;
private int hideHeaderHeight;
private LayoutParams headerLayoutParams;
private MyOnFreshListener myOnFreshListener;
private ScrollView scrollView;
private boolean isCancel,isFreshing;
private ListView listView;
private boolean ableToPul;
private Scroller mScroller;

public MyFreshLayoutScroller(Context context, AttributeSet attrs) {
    super(context, attrs);
    mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); 
    headView = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.view_head, null);
    headView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
    hideHeaderHeight = -headView.getMeasuredHeight();
    addView(headView);
    mScroller = new Scroller(context);
}

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    // TODO Auto-generated method stub
    super.onLayout(changed, l, t, r, b);
    if (headerLayoutParams == null) {
        init();
    }
}

public void setOnFreshListener(MyOnFreshListener myOnFreshListener) {
    this.myOnFreshListener = myOnFreshListener;
}

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {

    if (listView != null) {
        initAbleToPul();
    }
    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        iyDown = event.getRawY();
        yDown = event.getRawY();
        xDown = event.getRawX();
        break;
    case MotionEvent.ACTION_MOVE:
        float yMove = event.getRawY();
        float xMove = event.getRawX();
        int dy = (int) (yMove - iyDown);
        int dx = (int) (xMove-xDown); 
        boolean istoup = false;
        if (listView != null) {

            istoup = ableToPul;

        } else {
            istoup = scrollView.getScrollY() == 0;
        }
        if (dy > 0 && istoup&&dy>Math.abs(dx)) {
            return true;
        }

        break;
    case MotionEvent.ACTION_UP:

        break;

    default:
        break;
    }
    return false;
}

@Override
public boolean onTouchEvent(MotionEvent event) {

    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        yDown = event.getRawY();
        break;
    case MotionEvent.ACTION_MOVE:
        float yMove = event.getRawY();
        int distance = (int) (yMove - iyDown);
        if (distance <= 0) {
            break;
        }

        int d =(int) (yDown - event.getRawY());
        if(Math.abs(d)>=mTouchSlop){
        smoothScrollBy(0, d, 0);
        yDown = event.getRawY();
        }

        break;
    case MotionEvent.ACTION_UP:     
        if(yDown-iyDown>=-hideHeaderHeight){
            smoothScrollBy(0, -(int) mScroller.getFinalY() + hideHeaderHeight, 1000);
            handler.postDelayed(runnable, 1100);
        }else{
            smoothScrollBy(0, -(int) mScroller.getFinalY(), 1000);
        }

        break;

    default:
        break;
    }
    return false;
}

private void init() {
    headerLayoutParams = (LayoutParams) headView.getLayoutParams();
    headerLayoutParams.topMargin = hideHeaderHeight;
    headView.setLayoutParams(headerLayoutParams);
    if (getChildAt(1) instanceof ScrollView) {
        scrollView = (ScrollView) getChildAt(1);
    } else if (getChildAt(1) instanceof ListView) {
        listView = (ListView) getChildAt(1);
    } else {
        throw new IllegalArgumentException("下拉刷新只能包含一个子控件,而且该子控件必须为listview或者scrollView");
    }

}

private Handler handler = new Handler();

private Runnable runnable = new Runnable() {

    @Override
    public void run() {
        // TODO Auto-generated method stub
        if(myOnFreshListener!=null&&!isFreshing){
            isFreshing = true;
            myOnFreshListener.onFreshing();
        }
    }
};

private Runnable runnable2 = new Runnable() {

    @Override
    public void run() {
        if (isCancel) {
            isCancel = false;
            isFreshing = false;
            smoothScrollBy(0, -mScroller.getFinalY(), 1000);
        }
    }
};

public interface MyOnFreshListener {
    void onFreshing();
}

@Override
protected void onDetachedFromWindow() {
    super.onDetachedFromWindow();
    handler.removeCallbacksAndMessages(null);
}

public void cancelRefresh() {
    if (!isCancel) {
        isCancel = true;
        handler.postDelayed(runnable2, 1000);           
    }
}

private void initAbleToPul() {

    View firstChild = listView.getChildAt(0);
    if (firstChild == null) {
        ableToPul = true;
        return;
    }
    int firstVisiblePos = listView.getFirstVisiblePosition();
    ableToPul = (firstVisiblePos == 0 && firstChild.getTop() == 0);                 
}

private void smoothScrollBy(int dx, int dy, int time) {

    if (time == 0) {
        mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy);
    } else {
        mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy, time);
    }
    invalidate();
}

@Override
public void computeScroll() {
    if (mScroller.computeScrollOffset()) {
        scrollTo(mScroller.getCurrX(), mScroller.getCurrY());       
        invalidate();
    }       
    super.computeScroll();
}

}

这里大家其实也都看到了,整体上跟上一篇用marin实现的思路是一样的,外面套一层线性布局,上面是一个headview,我们通过判断手势在线性布局上的滑动方向来决定是是否要调用scroller来滑动listview,当我们手指按下的时候 首先将down事件传递给onInterceptTouchEvent方法中,首先判断listview是不是本身已经滑动到了顶部,如果是,此时再通过此方法的move事件来判断是向上滑动还是向下拉,如果不是,则返回false,事件传递给listview本身处理,否则返回true,传递给外层的线性布局的onTouchEvent处理,这里值得注意的是,onInterceptTouchEvent方法中,一点返回ture,那么该事件将被截断,不会再向下传递,直接传给本身的onTouchEvent,同时后续的 move以及up事件也不会再进入onInterceptTouchEvent。

最后,上源码地址:

http://download.csdn.net/detail/feiyang877647044/9484879

下一篇将为大家介绍上拉自动加载。

你可能感兴趣的:(下拉刷新)