具体自定义控件

Android 自定义 上拉加载容器

2020-03-13  本文已影响0人  小白彡

App中下拉刷新和上拉加载是很常见的功能,网上也有很多第三方库可以用,为了尽快完成项目,一般都是集成别人的库快速完成功能, 但有时候产品脑洞比较大 ,用别人的库又没那么灵活改起来也麻烦, 就只能自己来了。。。。。
下面看一下效果:


WeChat_20200313173628.gif

自定义还是挺麻烦的,不过也比较有意思,完成这个需要先了解几个知识点:
1.自定义ViewGroup
2.Scroller
3.事件分发体系。
下面开始简单的实现一下:
1.自定义ReboundLinearLayout 继承自 RelativeLayout 这个ViewGroup内部放需要上拉加载的Recyclerview

public class ReboundLinearLayout extends RelativeLayout {

2.由于事件传递的时候RecyclerView会把事件全部消耗完,所以要在ReboundLinearLayout的onInterceptTouchEvent中判断需要拦截的事件, 这里的思路是:如果RecyclerView已经滑动到最底部,就可以进行上拉加载了,这时候就可以拦截手指的向上滑动事件:

@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if(isSlideToBottom(reboundRecyclerView)){
            switch (ev.getAction()){
                case MotionEvent.ACTION_DOWN:
                    startY = ev.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    endY = ev.getY();
                    if(endY - startY >= 0){
                        return false;
                    }else if(endY - startY < 0){
                        return true;
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    break;
                default:
                    break;
            }
        }else{
            return false;
        }
        return false;
    }

3.在拦截完事件后,我们在onTouchEvent中进行事件的处理,当然就是使用scroller来将RecyclerView进行移动了:

@Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
                scrollEndY = event.getY();
                if(startY - scrollEndY <= SizeUtils.dp2px(scrollHeight)){
                    scrollTo(0, (int) (startY - scrollEndY));
                }
                break;
            case MotionEvent.ACTION_UP:
                mScroller.startScroll(0, getScrollY(),0, -getScrollY(),300);
                invalidate();
                if(onRefreshListenner != null){
                    onRefreshListenner.onRefresh();
                }
                break;
            default:
                break;
        }
        return true;
    }

这样就可以实现简单的上拉加载了,加个刷新监听 ,在刷新的时候请求数据,就完成啦。。。
下面贴一下代码

public class ReboundLinearLayout extends RelativeLayout {

    private RecyclerView reboundRecyclerView;
    //判断滑动方向
    private float startY;
    private float endY;

    private float scrollEndY;

    private Scroller mScroller;
    //最大拉动距离
    private int scrollHeight = 80;

    private OnRefreshListenner onRefreshListenner;

    public ReboundLinearLayout(Context context) {
        super(context);
    }

    public ReboundLinearLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        mScroller = new Scroller(context);
    }

    public ReboundLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if(isSlideToBottom(reboundRecyclerView)){
            switch (ev.getAction()){
                case MotionEvent.ACTION_DOWN:
                    startY = ev.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    endY = ev.getY();
                    if(endY - startY >= 0){
                        return false;
                    }else if(endY - startY < 0){
                        return true;
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    break;
                default:
                    break;
            }
        }else{
            return false;
        }
        return false;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
                scrollEndY = event.getY();
                if(startY - scrollEndY <= SizeUtils.dp2px(scrollHeight)){
                    scrollTo(0, (int) (startY - scrollEndY));
                }
                break;
            case MotionEvent.ACTION_UP:
                mScroller.startScroll(0, getScrollY(),0, -getScrollY(),300);
                invalidate();
                if(onRefreshListenner != null){
                    onRefreshListenner.onRefresh();
                }
                break;
            default:
                break;
        }
        return true;
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        reboundRecyclerView = (RecyclerView) getChildAt(0);
    }

    public static boolean isSlideToBottom(RecyclerView recyclerView) {
        if (recyclerView == null) return false;
        if (recyclerView.computeVerticalScrollExtent() + recyclerView.computeVerticalScrollOffset()
                >= recyclerView.computeVerticalScrollRange())
            return true;
        return false;
    }

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

    public void setOnRefreshListenner(OnRefreshListenner onRefreshListenner) {
        this.onRefreshListenner = onRefreshListenner;
    }

    public interface OnRefreshListenner{
        void onRefresh();
    }
}

结束。

上一篇下一篇

猜你喜欢

热点阅读