RecyclerView实现选中的item居中

本文介绍了如何在RecyclerView中实现首项和尾项自动滑动到中间位置的装饰器,以及使用自定义SnapHelper控制惯性滚动和特定控件的居中滚动,包括CenterDecoration和CenterLayoutManager类的实现方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、第1个item和最后一个item能够滑动至RecycleView中间位置。

实现:设置第1个item的左边距和最后一个item的右边距。

public class RecyclerItemCenterDecoration extends RecyclerView.ItemDecoration {
    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        // 获得Item的数量
        int itemCount = parent.getAdapter().getItemCount();
        if (itemCount > 0){
            // 获取当前Item的position
            int position = parent.getChildAdapterPosition(view);
            int endPosition = itemCount - 1;
            if (position == 0 || position == endPosition){
                // 测量view的宽度
                view.measure(0, 0);
                // 默认值
                int childViewWidth = DensityUtils.dip2px(120);
                if (view.getMeasuredWidth() > 0){
                    childViewWidth = view.getMeasuredWidth();
                }
                int parentWidth = parent.getWidth();
                if (parentWidth <= 0) {
                    parentWidth = DensityUtils.getScreenWidth(parent.getContext());
                }
                //所需的最小边距
                int minMargin = (parentWidth / 2 - childViewWidth / 2);
                RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams();
                // 第1个item左边距不够剧中
                if (position == 0 && layoutParams.leftMargin < minMargin){
                    layoutParams.setMargins(minMargin, layoutParams.topMargin, layoutParams.rightMargin, layoutParams.bottomMargin);
                    view.setLayoutParams(layoutParams);
                }
                // 最后的item右边距不够剧中
                if (position == endPosition && layoutParams.rightMargin < minMargin){
                    layoutParams.setMargins(layoutParams.leftMargin, layoutParams.topMargin, minMargin, layoutParams.bottomMargin);
                    view.setLayoutParams(layoutParams);
                }
            }
        }
        super.getItemOffsets(outRect, view, parent, state);
    }
}

二、(1)抬起手指时,能够让距离RecyclerView中心位置最近的控件正好居中(2)惯性滚动最多只能滚动1个item

实现:(1)LinearShapHelper可以实现控件自动修正至居中,但由于惯性加速度的影响使得目标view并非是距离中心位置最近的那个,需要重写findSnapView方法,实现指定我们想要选中的view(2)由于每个item的宽度都比RecyclerView小,PagerShapHelper无效。这里通过重写LinearShapHelper的findTargetSnapPosition方法,实现指定惯性滑动最终的view。

public class FlingOneLinearSnapHelper extends LinearSnapHelper {
    private RecyclerView mRecyclerView;

    @Override
    public void attachToRecyclerView(@Nullable RecyclerView recyclerView) throws IllegalStateException {
        mRecyclerView = recyclerView;
        super.attachToRecyclerView(recyclerView);
    }

    /**
     * 惯性滑动获取RecyclerView的最终位置
     *
     * @param layoutManager RecyclerView的布局管理器
     * @return 返回中心位置对应的控件
     */
    @Override
    public int findTargetSnapPosition(RecyclerView.LayoutManager layoutManager, int velocityX, int velocityY) {
        int resultPosition = RecyclerView.NO_POSITION;
        View centerView = findSnapView(layoutManager);
        if (centerView != null){
            int centerX = mRecyclerView.getMeasuredWidth() / 2;
            int viewCenterX = centerView.getLeft() + centerView.getWidth() / 2;
            int centerPotion = layoutManager.getPosition(centerView);
            if (velocityX > 0){
                // 向左滑
                if (viewCenterX < centerX) {
                    // 当前控件已经位于中线左边,则移动至下个位置
                    resultPosition = centerPotion + 1;
                } else {
                    resultPosition = centerPotion;
                }
            } else {
                // 向右滑
                if (viewCenterX > centerX) {
                    // 当前控件已经位于中线右边,则移动至上个位置
                    resultPosition = centerPotion - 1;
                } else {
                    resultPosition = centerPotion;
                }
            }
        }
        if (resultPosition < layoutManager.getItemCount()){
            return resultPosition;
        } else {
            return RecyclerView.NO_POSITION;
        }
    }

    /**
     * 获取RecyclerView的中心位置对应的控件
     *
     * @param layoutManager RecyclerView的布局管理器
     * @return 返回中心位置对应的控件
     */
    @Override
    public View findSnapView(RecyclerView.LayoutManager layoutManager) {
        int count = layoutManager.getChildCount();
        if (mRecyclerView != null && count > 0) {
            int centerX = mRecyclerView.getMeasuredWidth() / 2;
            if (centerX > 0){
                int distance = 0;
                for (int i = 0; i < count; i++){
                    View view = layoutManager.getChildAt(i);
                    if (view.getRight() < centerX){
                        distance = centerX - view.getRight();
                    } else {
                        if (view.getLeft() <= centerX){
                            return view;
                        } else {
                            int currentDistance = view.getLeft() - centerX;
                            if (currentDistance > distance){
                                return layoutManager.getChildAt(i - 1);
                            } else if (currentDistance < distance) {
                                return view;
                            }
                        }
                    }
                }
            }
        }
        return null;
    }

    /**
     * 获取RecyclerView的中心位置对应的item位置
     *
     * @param layoutManager RecyclerView的布局管理器
     * @return 返回中心位置对应的item位置
     */
    public int getCenterPotion(RecyclerView.LayoutManager layoutManager){
        View centerView = findSnapView(layoutManager);
        return centerView == null ? RecyclerView.NO_POSITION : layoutManager.getPosition(centerView);
    }

三、代码方式选中某个控件,能够将该控件滚动至居中

实现:重写LinearLayoutManager的smoothScrollToPosition方法,实现

recyclerView.smoothScrollToPosition(potion)能将控件滚动至中心位置
public class CenterLayoutManager extends LinearLayoutManager {


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

    public CenterLayoutManager(Context context, int orientation, boolean reverseLayout) {
        super(context, orientation, reverseLayout);


    }

    public CenterLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);

    }

    @Override
    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
        RecyclerView.SmoothScroller smoothScroller = new CenterSmoothScroller(recyclerView.getContext());
        smoothScroller.setTargetPosition(position);
        startSmoothScroll(smoothScroller);


    }

    private static class CenterSmoothScroller extends LinearSmoothScroller {

        CenterSmoothScroller(Context context) {
            super(context);
        }

        @Override
        public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference) {
            return (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2);
        }
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值