ScrollView下拉刷新

来源:互联网 发布:b站 解除限制 知乎 编辑:程序博客网 时间:2024/05/22 07:41
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);    }    /**    *首先是初始化mTouchSlop  是触摸手势滑动的最小像素值,也就是说滑动多少    *的距离才算是手势滑动,这样可以防止手势一点点的移动就引起的滑动事件。    *mScroller  是用来处理平滑滚动的。之前的博客有介绍。    **/    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());    }    /**    * 在布局初始化结束之后,得到布局中的两个子孩子,为啥只能有两个孩子那??    * BottomView是用来下拉刷新展示的View  contentView 就是我们的    * ScrollView了。如果子孩子多了,怎么知道哪个VIew是需要被隐藏的?所以只    * 处理两个View的情况,当然,如果还有上拉加载更多,就需要三个子孩子了。    **/    private ViewGroup bottomView ;    private ScrollView contentView ;     @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        getTopPosition();        return super.dispatchTouchEvent(ev);    }    @Override    protected void onFinishInflate() {        super.onFinishInflate();        if (getChildCount() > 2) {            throw new RuntimeException("子孩子只能有两个");        }        bottomView = (ViewGroup) getChildAt(0);        contentView = (ScrollView) getChildAt(1);    }    private int startY ;     @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);    }    @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 ;    }    private PullState state = PullState.REST ;     @Override    public void computeScroll() {        super.computeScroll();        if (mScroller.computeScrollOffset()) {            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());            postInvalidate();        }    }    private void returnView(){        restView(-getScrollY());    }    private void restView(int dy){        mScroller.startScroll(0, getScrollY(), 0, dy , 340);        postInvalidate();    }    private void pullMove(int delay){        if (getScrollY() <= 0 && (getScrollY() + delay) <= 0 ) {            scrollBy(0, delay);        }else {            scrollTo(0, 0);        }    }    /**    *手势的拦截动作,通过getTopPosition()方式,来判断ScrollView时候处于    *下拉需要显示隐藏子View的状态,delayY > mTouchSlop 是用来判断是不是    *下拉的动作的。 如果符合条件  我们就需要将手势拦截掉,return true。    *为什么我觉得ScrollView做下来刷新比较好做那? 就是因为ScrollView的判断比较好判断。    */    private boolean getTopPosition(){        if (contentView.getScrollY() <= 0 ) {            return true ;        }        return false ;    }    /**    *onLayout,做过自定义的都应该很熟悉这个方法,放置子孩子位置的一个方法,    *因为我们需要有一个子孩子隐藏掉,当我们需要它显示的时候才去显示,所以    *需要手动的去将BottomView放到布局-hight到0的位置,这样下拉的时候才能    *显示出来。    **/    @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);    }    private int bottomHeight = 0 ;    private int getBottomViewHeight(){        return bottomView.getMeasuredHeight();    }    enum PullState{        REST , ON_REFRESH     }    public void stopRefresh(){        state = PullState.REST;         returnView();    }    private onRefreshListener onreListener ;     public void setOnRefreshListener (onRefreshListener onreListener) {        this.onreListener = onreListener ;    }    public interface onRefreshListener{        public void refresh();    }}

源码下载

0 0
原创粉丝点击