横向加载更多(查看更多)RecyclerView

横向加载更多(查看更多)RecyclerView_第1张图片

实现方式是不改变RecyclerView本身,定义了一个父控件装载,查看更多和架子更多的view也同样作为该父控件的子控件。有简单的阻尼回弹效果。
实现代码:


public class PulToLeftViewGroupl extends LinearLayout implements ViewTreeObserver.OnGlobalLayoutListener {

    OnPullToLeftListener mOnPullToLeftListener;

    public void setOnPullToLeftListener(OnPullToLeftListener leftListener){
        this.mOnPullToLeftListener = leftListener;
    }

    public interface OnPullToLeftListener{
        /**
         * 松开手指去更新-可能需要动画在此函数实现
         */
        void onReleaseFingerToUpload();

        /**
         * 开始拉出查看更多-可能需要动画在此函数实现
         */
        void onStartToUpload();
    }

    /**
     * 动画时间
     */
    private static final long ANIM_TIME = 200;

    //recyclerview
    private View childView;

    // 用于记录正常的布局位置
    private Rect originalRect = new Rect();

    //滚动时,移动的view和位置
    private List mMoveViews = new ArrayList<>();
    private List mMoveRects = new ArrayList<>();

    // 在手指滑动的过程中记录是否移动了布局
    private boolean isMoved = false;

    // 如果按下时不能上拉和下拉, 会在手指移动时更新为当前手指的Y值
    private float startY;

    //阻尼
    private static final float OFFSET_RADIO = 0.6f;

    private boolean isRecyclerReuslt = false;

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

    public PulToLeftViewGroupl(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

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

    /**
     * 完成更新调用
     */
    public void completeToUpload(){

        postDelayed(new Runnable() {
            @Override
            public void run() {
                recoverLayout();
            }
        }, 1500);

    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);

        originalRect.set(childView.getLeft(), childView.getTop(), childView.getRight(), childView.getBottom());
        for (int i = 0; i < mMoveViews.size(); i++) {
            final View v = mMoveViews.get(i);
            v.addOnLayoutChangeListener(new OnLayoutChangeListener() {
                @Override
                public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                    Rect rect = new Rect();
                    rect.set(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
                    mMoveRects.add(rect);
                    v.removeOnLayoutChangeListener(this);
                }
            });
        }
    }

    /**
     * 加载布局后初始化,这个方法会在加载完布局后调用
     */
    @Override
    protected void onFinishInflate() {

        if (getChildCount() > 0) {
            for (int i = 0; i < getChildCount(); i++) {
                if (getChildAt(i) instanceof RecyclerView) {
                    if (childView == null) {
                        childView = getChildAt(i);
                    } else {
                        throw new RuntimeException("只能存在一个RecyclerView");
                    }
                }
            }
        }

        if (childView == null) {
            throw new RuntimeException("子容器中必须有一个RecyclerView");
        }
        //布局重绘监听,比如华为屏幕键盘可以弹出和隐藏,改变布局,加监听就可以虽键盘弹出关闭的变化而变化
        getViewTreeObserver().addOnGlobalLayoutListener(this);

        super.onFinishInflate();
    }

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
    @Override
    public void onGlobalLayout() {
        requestLayout();
        getViewTreeObserver().removeOnGlobalLayoutListener(this);
    }

    /**
     * 跟随弹性移动的view
     * @param view
     */
    public void setMoveViews(View view) {
        this.mMoveViews.add(view);
        requestLayout();
    }


    /**
     * 位置还原
     */
    private void recoverLayout() {

        if (!isMoved) {
            return;//如果没有移动布局,则跳过执行
        }

        for (int i = 0; i < mMoveViews.size(); i++) {
            if (i < mMoveRects.size()) {
                if (mMoveRects.get(i) != null) {
                    final int indexAt = i;

                    TranslateAnimation anims = new TranslateAnimation(mMoveViews.get(i).getRight(), mMoveRects.get(i).right, 0, 0);
                    anims.setDuration(ANIM_TIME);
                    mMoveViews.get(i).startAnimation(anims);
                    mMoveViews.get(indexAt).layout(
                            mMoveRects.get(indexAt).left,
                            mMoveRects.get(indexAt).top,
                            mMoveRects.get(indexAt).right,
                            mMoveRects.get(indexAt).bottom);

                }
            }
        }


        TranslateAnimation anim = new TranslateAnimation(childView.getRight() - originalRect.right, 0, 0,0);
        anim.setDuration(ANIM_TIME);
        childView.startAnimation(anim);
        childView.layout(originalRect.left, originalRect.top, originalRect.right, originalRect.bottom);
        isMoved = false;

    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return false;  //不拦截  直接传递给子的view
    }

    /**
     * 判断是否可以上拉
     * @return
     */
    private boolean isCanPullUp() {

        final RecyclerView.Adapter adapter = ((RecyclerView) childView).getAdapter();

        if (null == adapter) {
            return true;
        }

        final int lastItemPosition = adapter.getItemCount() - 1;
        final int lastVisiblePosition = ((LinearLayoutManager) ((RecyclerView) childView)
                .getLayoutManager()).findLastVisibleItemPosition();

        if (lastVisiblePosition >= lastItemPosition) {

            final int childIndex = lastVisiblePosition - ((LinearLayoutManager) ((RecyclerView) childView)
                    .getLayoutManager()).findFirstVisibleItemPosition();

            final int childCount = ((RecyclerView) childView).getChildCount();
            final int index = Math.max(childIndex, childCount - 1);
            final View lastVisibleChild = ((RecyclerView) childView).getChildAt(index);
            if (lastVisibleChild != null) {
                return lastVisibleChild.getRight() <= childView.getRight() - childView.getLeft();
            }
        }

        return false;
    }

    /**
     * 事件分发
     */

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (childView == null) {
            return super.dispatchTouchEvent(ev);
        }

        boolean isTouchOutOfScrollView = ev.getX() >= originalRect.right || ev.getX() <= originalRect.left; //如果当前view的Y上的位置
        if (isTouchOutOfScrollView) {//如果不在view的范围内
            if (isMoved) {      //当前容器已经被移动
                recoverLayout();
            }
            return true;
        }

        int action = ev.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                //记录按下时的X
                startY = ev.getX();
            case MotionEvent.ACTION_MOVE:
                float nowX = ev.getX();
                int scrollX = (int) (nowX - startY);
                if ((isCanPullUp() && scrollX < 0)) {

                    int offset = (int) (scrollX * OFFSET_RADIO);

                    childView.layout(originalRect.left + offset, originalRect.top, originalRect.right + offset, originalRect.bottom);


                    for (int i = 0; i < mMoveViews.size(); i++) {
                        if (i < mMoveRects.size()) {
                                if (mMoveViews.get(i) != null && mMoveRects.get(i) != null) {
                                    mMoveViews.get(i).layout(mMoveRects.get(i).left + offset,
                                            mMoveRects.get(i).top,
                                            mMoveRects.get(i).right + offset,
                                            mMoveRects.get(i).bottom);
                                }
                        }
                    }

                    isMoved = true;
                    isRecyclerReuslt = false;

                    if (mOnPullToLeftListener!=null){
                        mOnPullToLeftListener.onStartToUpload();
                    }

                    return true;
                } else {
                    startY = ev.getX();
                    isMoved = false;
                    isRecyclerReuslt = true;
                    recoverLayout();
                    return super.dispatchTouchEvent(ev);
                }
            case MotionEvent.ACTION_UP:

                if (isMoved && mOnPullToLeftListener!=null) {
                    //recoverLayout();
                    mOnPullToLeftListener.onReleaseFingerToUpload();
                }

                if (isRecyclerReuslt) {
                    return super.dispatchTouchEvent(ev);
                } else {
                    return true;
                }
            default:
                return true;
        }
    }

}

需要注意的地方有RecyclerView的Manager只处理了LinearLayoutManager.如果需要其他类型的Manager,请自行改写isCanPullUp()函数。

横向加载更多(查看更多)RecyclerView_第2张图片

eg使用例子:
布局文件xml中代码:

 .PulToLeftViewGroupl
        android:id="@+id/pull_group"
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        .support.v7.widget.RecyclerView
            android:scrollbars="none"
            android:background="#FFFFFF"
            android:overScrollMode="never"
            android:id="@+id/rv_hsv_type_content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">.support.v7.widget.RecyclerView>

        "@layout/include_left_layout"/>
    .PulToLeftViewGroupl>

Activity中代码:

mRecyclerView = (RecyclerView) findViewById(R.id.rv_hsv_type_content);
        moved_view = (RelativeLayout) findViewById(R.id.moved_view);
        pull_group = (PulToLeftViewGroupl) findViewById(R.id.pull_group) ;
        pull_group.setMoveViews(moved_view);
        List strings = new LinkedList<>();
        for (int ii=0; ii<6; ii++) {
            String str = "";
            strings.add(str);
        }
        mAdapter = new Adapter(strings);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
        mRecyclerView.addItemDecoration(new Adapter.SpacesItemDecoration(0, 50, 0, 0));
        mRecyclerView.setAdapter(mAdapter);
        pull_group.setOnPullToLeftListener(new PulToLeftViewGroupl.OnPullToLeftListener() {
            @Override
            public void onReleaseFingerToUpload() {
                for (int ii=0; ii<6; ii++) {
                    String str = "";
                    mAdapter.addItem(str);
                }

                mAdapter.notifyDataSetChanged();
                pull_group.completeToUpload();
            }

            @Override
            public void onStartToUpload() {

            }
        });
    }

include对应布局就是pull_group.setMoveViews…的注入View。

你可能感兴趣的:(Android)