recyclerview水平滚动到左边 [英] recyclerview horizontal scrolling to left

查看:1187
本文介绍了recyclerview水平滚动到左边的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在创建一个应用程序,我正在使用带有snaphelper类的recyclerview来制作可滚动的水平cardstack我已经成功实现了但是我的问题是卡向右滑动方向我想要向左滑动卡片。
我对SO做了一些研究,发现这个
RecyclerView水平滚动卡在中心
SnapHelper项目位置
但我还是不能弄清楚如何将滚动位置设置为左而不是右边
请任何帮助将被赞赏
更新:我仍然在努力这个几乎没有弄清楚因为它仍然很难改变方向在recyclerview中滚动所以任何人仍然希望帮助我。
我还发现findsnapView方法传递滚动位置和方向可能我错了但是代码可能是解决方案

I'm making an app where I'm using recyclerview with snaphelper class to make scrollable horizontal cardstack I'have implemented that successfully however my problem is that the cards swipe to right direction and I want to swipe the cards on left direction. I did some research on SO and found this RecyclerView horizontal scroll snap in center SnapHelper Item Position But I still couldnt figure out how to set the scrolling position to left instead of right Please any help would be appreciated Update:i'm still working on this hardly figured out much because it is still difficult to change the direction of scrolling in recyclerview so anyone still wants to help me are welcome. I also found that findsnapView method passes the scroll position and direcion maybe i'm wrong but beow code mght be the solution

**@Override
    public View findSnapView(RecyclerView.LayoutManager layoutManager) {
        if (layoutManager instanceof LadderLayoutManager) {
            int pos = ((LadderLayoutManager) layoutManager).getFixedScrollPosition(
                    mDirection, mDirection != 0 ? 0.8f : 0.5f);
            mDirection = 0;
            if (pos != RecyclerView.NO_POSITION) {
                return layoutManager.findViewByPosition(pos);
            }
        }
        return null;
    }**

我的主要课程

public class MainActivity extends AppCompatActivity {
    LadderLayoutManager llm;
    RecyclerView rcv;
    HSAdapter adapter;
    int scrollToPosition;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        llm = new LadderLayoutManager(1.5f, 0.85f, LadderLayoutManager.HORIZONTAL).
                setChildDecorateHelper(new LadderLayoutManager
                        .DefaultChildDecorateHelper(getResources().getDimension(R.dimen.item_max_elevation)));
        llm.setChildPeekSize((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                30, getResources().getDisplayMetrics()));
        llm.setMaxItemLayoutCount(5);

        rcv = (RecyclerView) findViewById(R.id.rcv);
        rcv.setLayoutManager(llm);

        new LadderSimpleSnapHelper().attachToRecyclerView(rcv);
        adapter = new HSAdapter();
        rcv.setAdapter(adapter);

        final SeekBar sb = (SeekBar) findViewById(R.id.sb);
    }

自定义LayoutManager的代码

My code for custom LayoutManager

public class LadderLayoutManager extends RecyclerView.LayoutManager implements RecyclerView.SmoothScroller.ScrollVectorProvider {
    private static final int INVALIDATE_SCROLL_OFFSET = Integer.MAX_VALUE;
    private static final float DEFAULT_CHILD_LAYOUT_OFFSET = 0.2f;
    public static final int UNLIMITED = 0;
    public static final int VERTICAL = 1;
    public static final int HORIZONTAL = 0;
    private boolean mCheckedChildSize;
    private int[] mChildSize;
    private int mChildPeekSize;
    private int mChildPeekSizeInput;
    private boolean mReverse;
    private int mScrollOffset = INVALIDATE_SCROLL_OFFSET;
    private float mItemHeightWidthRatio;
    private float mScale;
    private int mChildCount;
    private float mVanishOffset = 0;
    private Interpolator mInterpolator;
    private int mOrientation;
    private ChildDecorateHelper mDecorateHelper;
    private int mMaxItemLayoutCount;

    public LadderLayoutManager(float itemHeightWidthRatio) {
        this(itemHeightWidthRatio, 0.9f, VERTICAL);
    }


    public LadderLayoutManager(float itemHeightWidthRatio, float scale, int orientation) {
        this.mItemHeightWidthRatio = itemHeightWidthRatio;
        this.mOrientation = orientation;
        this.mScale = scale;
        this.mChildSize = new int[2];
        this.mInterpolator = new DecelerateInterpolator();
    }

    @Override
    public RecyclerView.LayoutParams generateDefaultLayoutParams() {
        return new RecyclerView.LayoutParams(mChildSize[0], mChildSize[1]);
    }

    public LadderLayoutManager setChildDecorateHelper(ChildDecorateHelper layoutHelper) {
        mDecorateHelper = layoutHelper;
        return this;
    }

    public void setMaxItemLayoutCount(int count) {
        mMaxItemLayoutCount = Math.max(2, count);
        if (getChildCount() > 0) {
            requestLayout();
        }
    }


    public void setVanishOffset(float offset) {
        mVanishOffset = offset;
        if (getChildCount() > 0) {
            requestLayout();
        }
    }


    public void setChildPeekSize(int childPeekSize) {
        mChildPeekSizeInput = childPeekSize;
        mCheckedChildSize = false;
        if (getChildCount() > 0) {
            requestLayout();
        }
    }


    public void setItemHeightWidthRatio(float itemHeightWidthRatio) {
        mItemHeightWidthRatio = itemHeightWidthRatio;
        mCheckedChildSize = false;
        if (getChildCount() > 0) {
            requestLayout();
        }
    }


    public void setReverse(boolean reverse) {
        if (mReverse != reverse) {
            mReverse = reverse;
            if (getChildCount() > 0) {
                requestLayout();
            }
        }
    }

    public boolean isReverse() {
        return mReverse;
    }



    public int getFixedScrollPosition(int direction, float fixValue) {
        if (mCheckedChildSize) {
            if (mScrollOffset % mChildSize[mOrientation] == 0) {
                return RecyclerView.NO_POSITION;
            }
            float position = mScrollOffset * 1.0f / mChildSize[mOrientation];
            return convert2AdapterPosition((int) (direction > 0 ? position + fixValue : position + (1 - fixValue)) - 1);
        }
        return RecyclerView.NO_POSITION;
    }


    @Override
    public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {
        super.onMeasure(recycler, state, widthSpec, heightSpec);
        mCheckedChildSize = false;
    }

    @Override
    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
        if (state.getItemCount() == 0) {
            removeAndRecycleAllViews(recycler);
            return;
        }
        if (!mCheckedChildSize) {
            if (mOrientation == VERTICAL) {
                mChildSize[0] = getHorizontalSpace();
                mChildSize[1] = (int) (mItemHeightWidthRatio * mChildSize[0]);
            } else {
                mChildSize[1] = getVerticalSpace();
                mChildSize[0] = (int) (mChildSize[1] / mItemHeightWidthRatio);
            }
            mChildPeekSize = mChildPeekSizeInput == 0 ?
                    (int) (mChildSize[mOrientation] * DEFAULT_CHILD_LAYOUT_OFFSET) : mChildPeekSizeInput;
            mCheckedChildSize = true;
        }
        int itemCount = getItemCount();
        if (mReverse) {
            mScrollOffset += (itemCount - mChildCount) * mChildSize[mOrientation];
        }
        mChildCount = itemCount;
        mScrollOffset = makeScrollOffsetWithinRange(mScrollOffset);
        fill(recycler);
    }

    public void fill(RecyclerView.Recycler recycler) {
        int bottomItemPosition = (int) Math.floor(mScrollOffset / mChildSize[mOrientation]);//>=1
        int bottomItemVisibleSize = mScrollOffset % mChildSize[mOrientation];
        final float offsetPercent = mInterpolator.getInterpolation(
                bottomItemVisibleSize * 1.0f / mChildSize[mOrientation]);//[0,1)
        final int space = mOrientation == VERTICAL ? getVerticalSpace() : getHorizontalSpace();

        ArrayList<ItemLayoutInfo> layoutInfos = new ArrayList<>();
        for (int i = bottomItemPosition - 1, j = 1, remainSpace = space - mChildSize[mOrientation];
             i >= 0; i--, j++) {
            double maxOffset = mChildPeekSize * Math.pow(mScale, j);
            int start = (int) (remainSpace - offsetPercent * maxOffset);
            ItemLayoutInfo info = new ItemLayoutInfo(start,
                    (float) (Math.pow(mScale, j - 1) * (1 - offsetPercent * (1 - mScale))),
                    offsetPercent,
                    start * 1.0f / space
            );
            layoutInfos.add(0, info);

            if (mMaxItemLayoutCount != UNLIMITED && j == mMaxItemLayoutCount - 1) {
                if (offsetPercent != 0) {
                    info.start = remainSpace;
                    info.positionOffsetPercent = 0;
                    info.layoutPercent = remainSpace / space;
                    info.scaleXY = (float) Math.pow(mScale, j - 1);
                }
                break;
            }
            remainSpace -= maxOffset;
            if (remainSpace <= 0) {
                info.start = (int) (remainSpace + maxOffset);
                info.positionOffsetPercent = 0;
                info.layoutPercent = info.start / space;
                info.scaleXY = (float) Math.pow(mScale, j - 1);
                break;
            }
        }

        if (bottomItemPosition < mChildCount) {
            final int start = space - bottomItemVisibleSize;
            layoutInfos.add(new ItemLayoutInfo(start, 1.0f,
                    bottomItemVisibleSize * 1.0f / mChildSize[mOrientation], start * 1.0f / space).
                    setIsBottom());
        } else {
            bottomItemPosition -= 1;
        }

        int layoutCount = layoutInfos.size();

        final int startPos = bottomItemPosition - (layoutCount - 1);
        final int endPos = bottomItemPosition;
        final int childCount = getChildCount();
        for (int i = childCount - 1; i >= 0; i--) {
            View childView = getChildAt(i);
            int pos = convert2LayoutPosition(getPosition(childView));
            if (pos > endPos || pos < startPos) {
                removeAndRecycleView(childView, recycler);
            }
        }
        detachAndScrapAttachedViews(recycler);

        for (int i = 0; i < layoutCount; i++) {
            fillChild(recycler.getViewForPosition(convert2AdapterPosition(startPos + i)), layoutInfos.get(i));
        }
    }

    private void fillChild(View view, ItemLayoutInfo layoutInfo) {
        addView(view);
        measureChildWithExactlySize(view);
        final int scaleFix = (int) (mChildSize[mOrientation] * (1 - layoutInfo.scaleXY) / 2);
        final float gap = (mOrientation == VERTICAL ? getHorizontalSpace() : getVerticalSpace())
                - mChildSize[(mOrientation + 1) % 2] * layoutInfo.scaleXY;

        if (mOrientation == VERTICAL) {
            int left = (int) (getPaddingLeft() + (gap * 0.5 * mVanishOffset));
            layoutDecoratedWithMargins(view, left, layoutInfo.start - scaleFix
                    , left + mChildSize[0], layoutInfo.start + mChildSize[1] - scaleFix);
        } else {
            int top = (int) (getPaddingTop() + (gap * 0.5 * mVanishOffset));
            layoutDecoratedWithMargins(view, layoutInfo.start - scaleFix, top
                    , layoutInfo.start + mChildSize[0] - scaleFix, top + mChildSize[1]);
        }
        ViewCompat.setScaleX(view, layoutInfo.scaleXY);
        ViewCompat.setScaleY(view, layoutInfo.scaleXY);
        if (mDecorateHelper != null) {
            mDecorateHelper.decorateChild(view, layoutInfo.positionOffsetPercent, layoutInfo.layoutPercent, layoutInfo.isBottom);
        }
    }

    private void measureChildWithExactlySize(View child) {
        RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) child.getLayoutParams();
        final int widthSpec = View.MeasureSpec.makeMeasureSpec(
                mChildSize[0] - lp.leftMargin - lp.rightMargin, View.MeasureSpec.EXACTLY);
        final int heightSpec = View.MeasureSpec.makeMeasureSpec(
                mChildSize[1] - lp.topMargin - lp.bottomMargin, View.MeasureSpec.EXACTLY);
        child.measure(widthSpec, heightSpec);
    }

    private int makeScrollOffsetWithinRange(int scrollOffset) {
        return Math.min(Math.max(mChildSize[mOrientation], scrollOffset), mChildCount * mChildSize[mOrientation]);
    }


    @Override
    public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
        int pendingScrollOffset = mScrollOffset + dy;
        mScrollOffset = makeScrollOffsetWithinRange(pendingScrollOffset);
        fill(recycler);
        return mScrollOffset - pendingScrollOffset + dy;
    }

    @Override
    public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
        int pendingScrollOffset = mScrollOffset + dx;
        mScrollOffset = makeScrollOffsetWithinRange(pendingScrollOffset);
        fill(recycler);
        return mScrollOffset - pendingScrollOffset + dx;
    }

    @Override
    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
        final LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext()) {
            @Override
            public int calculateDyToMakeVisible(final View view, final int snapPreference) {
                if (mOrientation == VERTICAL) {
                    return -calculateDistanceToPosition(getPosition(view));
                }
                return 0;
            }

            @Override
            public int calculateDxToMakeVisible(final View view, final int snapPreference) {
                if (mOrientation == HORIZONTAL) {
                    return -calculateDistanceToPosition(getPosition(view));
                }
                return 0;
            }
        };
        linearSmoothScroller.setTargetPosition(position);
        startSmoothScroll(linearSmoothScroller);
    }


    public int calculateDistanceToPosition(int targetPos) {
        int pendingScrollOffset = mChildSize[mOrientation] * (convert2LayoutPosition(targetPos) + 1);
        return pendingScrollOffset - mScrollOffset;
    }


    @Override
    public void scrollToPosition(int position) {
        if (position > 0 && position < mChildCount) {
            mScrollOffset = mChildSize[mOrientation] * (convert2LayoutPosition(position) + 1);
            requestLayout();
        }
    }


    @Override
    public boolean canScrollVertically() {
        return mOrientation == VERTICAL;
    }

    @Override
    public boolean canScrollHorizontally() {
        return mOrientation == HORIZONTAL;
    }

    public int convert2AdapterPosition(int layoutPosition) {
        return mReverse ? mChildCount - 1 - layoutPosition : layoutPosition;
    }

    public int convert2LayoutPosition(int adapterPostion) {
        return mReverse ? mChildCount - 1 - adapterPostion : adapterPostion;
    }

    public int getVerticalSpace() {
        return getHeight() - getPaddingTop() - getPaddingBottom();
    }

    public int getHorizontalSpace() {
        return getWidth() - getPaddingLeft() - getPaddingRight();
    }

    @Override
    public PointF computeScrollVectorForPosition(int targetPosition) {
        int pos = convert2LayoutPosition(targetPosition);
        int scrollOffset = (pos + 1) * mChildSize[mOrientation];
        return mOrientation == VERTICAL ? new PointF(0, Math.signum(scrollOffset - mScrollOffset))
                : new PointF(Math.signum(scrollOffset - mScrollOffset), 0);
    }

    private static class ItemLayoutInfo {
        float scaleXY;
        float layoutPercent;
        float positionOffsetPercent;
        int start;
        boolean isBottom;

        ItemLayoutInfo(int top, float scale, float positonOffset, float percent) {
            this.start = top;
            this.scaleXY = scale;
            this.positionOffsetPercent = positonOffset;
            this.layoutPercent = percent;
        }

        ItemLayoutInfo setIsBottom() {
            isBottom = true;
            return this;
        }

    }


    @Override
    public Parcelable onSaveInstanceState() {
        SavedState savedState = new SavedState();
        savedState.scrollOffset = mScrollOffset;
        savedState.reverse = mReverse;
        savedState.vanishOffset = mVanishOffset;
        savedState.scale = mScale;
        savedState.childLayoutOffsetInput = mChildPeekSizeInput;
        savedState.itemHeightWidthRatio = mItemHeightWidthRatio;
        savedState.orientation = mOrientation;
        return savedState;
    }

    @Override
    public void onRestoreInstanceState(Parcelable state) {
        if (state instanceof SavedState) {
            SavedState s = (SavedState) state;
            mScrollOffset = s.scrollOffset;
            mReverse = s.reverse;
            mVanishOffset = s.vanishOffset;
            mScale = s.scale;
            mChildPeekSizeInput = s.childLayoutOffsetInput;
            mItemHeightWidthRatio = s.itemHeightWidthRatio;
            mOrientation = s.orientation;
            requestLayout();
        }
    }

    public static class SavedState implements Parcelable {

        int scrollOffset, childLayoutOffsetInput, orientation;
        float itemHeightWidthRatio, scale, elevation, vanishOffset;
        boolean reverse;

        public SavedState() {
        }

        SavedState(LadderLayoutManager.SavedState other) {
            scrollOffset = other.scrollOffset;
            childLayoutOffsetInput = other.childLayoutOffsetInput;
            orientation = other.orientation;
            itemHeightWidthRatio = other.itemHeightWidthRatio;
            scale = other.scale;
            elevation = other.elevation;
            vanishOffset = other.vanishOffset;
            reverse = other.reverse;
        }

        SavedState(Parcel in) {
            scrollOffset = in.readInt();
            childLayoutOffsetInput = in.readInt();
            orientation = in.readInt();
            itemHeightWidthRatio = in.readFloat();
            scale = in.readFloat();
            elevation = in.readFloat();
            vanishOffset = in.readFloat();
            reverse = in.readInt() == 1;
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeInt(scrollOffset);
            dest.writeInt(childLayoutOffsetInput);
            dest.writeInt(orientation);
            dest.writeFloat(itemHeightWidthRatio);
            dest.writeFloat(scale);
            dest.writeFloat(elevation);
            dest.writeFloat(vanishOffset);
            dest.writeInt(reverse ? 1 : 0);
        }

        @Override
        public int describeContents() {
            return 0;
        }

        public static final Creator<SavedState> CREATOR
                = new Creator<SavedState>() {
            @Override
            public LadderLayoutManager.SavedState createFromParcel(Parcel in) {
                return new LadderLayoutManager.SavedState(in);
            }

            @Override
            public LadderLayoutManager.SavedState[] newArray(int size) {
                return new LadderLayoutManager.SavedState[size];
            }
        };
    }


    public interface ChildDecorateHelper {

        void decorateChild(View child, float posOffsetPercent, float layoutPercent, boolean isBottom);
    }

    public static class DefaultChildDecorateHelper implements ChildDecorateHelper {
        private float mElevation;

        public DefaultChildDecorateHelper(float maxElevation) {
            mElevation = maxElevation;
        }

        @Override
        public void decorateChild(View child, float posOffsetPercent, float layoutPercent, boolean isBottom) {
            ViewCompat.setElevation(child, (float) (layoutPercent * mElevation * 0.7 + mElevation * 0.3));
        }
    }
}

这是我的snaphelper代码

Here is my code for snaphelper

public class LadderSimpleSnapHelper extends SnapHelper {
    private int mDirection;
    //int position = layoutManager.getPosition(centerView);
    @Override
    public int[] calculateDistanceToFinalSnap(
            @NonNull RecyclerView.LayoutManager layoutManager, @NonNull View targetView) {

        if (layoutManager instanceof LadderLayoutManager) {
            int[] out = new int[2];
            if (layoutManager.canScrollHorizontally()) {
                out[0] = ((LadderLayoutManager) layoutManager).calculateDistanceToPosition(
                        layoutManager.getPosition(targetView));
                out[1] = 0;
            } else {
                out[0] = 0;
                out[1] = ((LadderLayoutManager) layoutManager).calculateDistanceToPosition(
                        layoutManager.getPosition(targetView));
            }
            return out;
        }
        return null;
    }

    @Override
    public int findTargetSnapPosition(RecyclerView.LayoutManager layoutManager, int velocityX,
                                      int velocityY) {
        if (layoutManager.canScrollHorizontally()) {

                mDirection = velocityX;
            } else {
                mDirection = velocityY;
            }
        return RecyclerView.NO_POSITION;
    }

    @Override
    public View findSnapView(RecyclerView.LayoutManager layoutManager) {
        if (layoutManager instanceof LadderLayoutManager) {
            int pos = ((LadderLayoutManager) layoutManager).getFixedScrollPosition(
                    mDirection, mDirection != 0 ? 0.8f : 0.5f);
            mDirection = 0;
            if (pos != RecyclerView.NO_POSITION) {
                return layoutManager.findViewByPosition(pos);
            }
        }
        return null;
    }
}


推荐答案

使用代码如下:

mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, true));

这篇关于recyclerview水平滚动到左边的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆