RecyclerView滑动

本文介绍RecyclerView滑动控制方法,包括直接定位、偏移量滑动、平滑滑动及居中显示等技巧,并提供多种实现方式,适用于不同场景。

方法

  • scrollToPosition
    不在屏幕Item移至屏幕,原上方Item移至可见头项,原下方移至屏幕可见末项。已显Item不移。
  • scrollToPositionWithOffset
    Item移至可见头项(即使已于可见Item中)。参数offset表Item移至头项后同RecyclerView上或下边间距(默0)。
  • scrollBy
    据偏移量移。
  • scrollTo
    移至坐标点。

场景一

滑至某位。

实现一

布局管理器

((LinearLayoutManager) rvParaConfigComplexType.getLayoutManager()).scrollToPositionWithOffset(position, 0);
((LinearLayoutManager) rvParaConfigComplexType.getLayoutManager()).setStackFromEnd(true);
complexTypeList.add(position, complexType);  
paraConfigChooseComplexTypeAdapter.notifyItemInserted(position);     
paraConfigChooseComplexTypeAdapter.notifyItemRangeChanged(position, complexTypeList.size() - position);
实现二

据当前RecyclerView条数(有效避指针越界)

package util;

import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;

/**
 * Created on 2018/6/28.
 *
 * @desc RecyclerViewScrollController
 */
public class RecyclerViewScrollController {
    /**
     * 滑至某位
     *
     * @param manager       布局管理器
     * @param mRecyclerView recyclerView
     * @param n             位
     */
    public static void ScrollToPosition(LinearLayoutManager manager, RecyclerView mRecyclerView, int n) {
        int firstItem = manager.findFirstVisibleItemPosition();
        int lastItem = manager.findLastVisibleItemPosition();
        if (n <= firstItem) {
            mRecyclerView.scrollToPosition(n);
        } else if (n <= lastItem) {
            int top = mRecyclerView.getChildAt(n - firstItem).getTop();
            mRecyclerView.scrollBy(0, top);
        } else {
            mRecyclerView.scrollToPosition(n);
        }
    }
}
RecyclerViewScrollController.ScrollToPosition(((LinearLayoutManager) rvParaConfigComplexType.getLayoutManager()), rvParaConfigComplexType, 0);
实现三
平滑一
package widget.recyclerview;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

/**
 * Created on 2018/6/28.
 *
 * @author 郑少鹏
 * @desc RecyclerViewScrollController
 */
public class RecyclerViewScrollController {
    /**
     * 应滑否(目标项于最后一可见项后否)
     */
    private boolean shouldScroll;
    /**
     * 目标位
     */
    private int targetPosition;
        
    /**
     * 平滑至目标位
     *
     * @param recyclerView 控件
     * @param position     位
     */
    private void smoothScrollToTargetPosition(RecyclerView recyclerView, final int position) {
        // 头可见项
        int firstItem = recyclerView.getChildLayoutPosition(recyclerView.getChildAt(0));
        // 末可见项
        int lastItem = recyclerView.getChildLayoutPosition(recyclerView.getChildAt(recyclerView.getChildCount() - 1));
        if (position < firstItem) {
            // 跳转位于头可见项前时smoothScrollToPosition可直跳
            recyclerView.smoothScrollToPosition(position);
        } else if (position <= lastItem) {
            // 跳转位于头可见项后末可见项前时,smoothScrollToPosition根本不动,此时调smoothScrollBy滑至指定位
            int movePosition = position - firstItem;
            if (movePosition >= 0 && movePosition < recyclerView.getChildCount()) {
                int top = recyclerView.getChildAt(movePosition).getTop();
                recyclerView.smoothScrollBy(0, top);
            }
        } else {
            // 跳转位于末可见项后时先调smoothScrollToPosition将跳转位滑至可见位
            // 再通onScrollStateChanged控制再调smoothMoveToPosition执行上判断中法
            recyclerView.smoothScrollToPosition(position);
            targetPosition = position;
            shouldScroll = true;
        }
        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                if (shouldScroll) {
                    shouldScroll = false;
                    flatSlidingToTargetPosition(recyclerView, targetPosition);
                }
            }
        });
    }
}
RecyclerViewScrollController recyclerViewScrollController = new RecyclerViewScrollController();
recyclerViewScrollController.smoothScrollToTargetPosition(pharmaceuticalKnowledgeTwoLevelClassificationFragmentRv, position);                
平滑二
package widget.recyclerview;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

/**
 * Created on 2018/6/28.
 *
 * @author 郑少鹏
 * @desc RecyclerViewScrollController
 */
public class RecyclerViewScrollController {
    private boolean move;
    private int index;

    /**
     * 平滑至目标位
     *
     * @param recyclerView 控件
     * @param position     位
     */
    public void smoothScrollToTargetPosition(RecyclerView recyclerView, int position) {
        LinearLayoutManager manager = (LinearLayoutManager) recyclerView.getLayoutManager();
        if (manager != null) {
            // 滑至指定位
            // 记录(第三种情况用到)
            this.index = position;
            // 当前屏幕可见头项与末项
            int firstItem = manager.findFirstVisibleItemPosition();
            int lastItem = manager.findLastVisibleItemPosition();
            // 区分
            if (position <= firstItem) {
                // 所置顶项于当前显示头项前
                recyclerView.smoothScrollToPosition(position);
            } else if (position <= lastItem) {
                // 所置顶项已于屏幕上
                int top = recyclerView.getChildAt(position - firstItem).getTop();
                recyclerView.smoothScrollBy(0, top);
            } else {
                // 所置顶项于当前显示末项后
                recyclerView.smoothScrollToPosition(position);
                move = true;
            }
            // 滑动监听
            recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                    super.onScrollStateChanged(recyclerView, newState);
                    // 此处第二次滚动
                    if (move) {
                        move = false;
                        // 所置顶项于当前屏幕位,mIndex记录所置顶于RecyclerView中位
                        int n = index - manager.findFirstVisibleItemPosition();
                        if (0 <= n && n < recyclerView.getChildCount()) {
                            // 所置顶项顶距RecyclerView顶距离
                            int top = recyclerView.getChildAt(n).getTop();
                            // 最后移动
                            recyclerView.smoothScrollBy(0, top);
                        }
                    }
                }
            });
        }
    }
}
RecyclerViewScrollController recyclerViewScrollController = new RecyclerViewScrollController();
recyclerViewScrollController.smoothScrollToTargetPosition(pharmaceuticalKnowledgeTwoLevelClassificationFragmentRv, position);
平滑三
/**
 * 通滑动模式平滑至目标位
 *
 * @param recyclerView   控件
 * @param targetPosition 目标位
 * @param scrollMode     滑动模式(默SNAP_TO_ANY)
 *                       {@link LinearSmoothScroller#SNAP_TO_START}
 *                       子视图左侧或顶部对齐父视图左侧或顶部。
 *                       {@link LinearSmoothScroller#SNAP_TO_END}
 *                       子视图右侧或底部对齐父视图右侧面或底部。
 *                       {@link LinearSmoothScroller#SNAP_TO_ANY}
 *                       据子视图当前位与父布局关系定子视图从头到尾跟随否。
 *                       子视图实际于RecyclerView左侧,SNAP_TO_ANY和SNAP_TO_START无差别。
 */
public void smoothScrollToTargetPositionWithScrollMode(RecyclerView recyclerView, int targetPosition, int scrollMode) {
    LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
    if (null == linearLayoutManager) {
        return;
    }
    LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext()) {
        @Override
        protected int getVerticalSnapPreference() {
            return scrollMode;
        }

        @Override
        public PointF computeScrollVectorForPosition(int targetPosition) {
            return linearLayoutManager.computeScrollVectorForPosition(targetPosition);
        }
    };
    recyclerView.setLayoutManager(linearLayoutManager);
    // 滑
    linearSmoothScroller.setTargetPosition(targetPosition);
    linearLayoutManager.startSmoothScroll(linearSmoothScroller);
}
RecyclerViewScrollController recyclerViewScrollController = new RecyclerViewScrollController();
recyclerViewScrollController.smoothScrollToTargetPositionWithScrollMode(contactActivityRv, contactBeanList.size() - 1, LinearSmoothScroller.SNAP_TO_START);

场景二

条目滑至居中

实现
/**
 * 条目滑至居中
 *
 * @param recyclerView 控件
 * @param position     位
 */
public void itemScrollToCenter(RecyclerView recyclerView, int position) {
    LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
    if (linearLayoutManager != null) {
        int firstPosition = linearLayoutManager.findFirstVisibleItemPosition();
        int lastPosition = linearLayoutManager.findLastVisibleItemPosition();
        int left = recyclerView.getChildAt(position - firstPosition).getLeft();
        int right = recyclerView.getChildAt(lastPosition - position).getLeft();
        recyclerView.scrollBy((left - right) / 2, 0);
    }
}

工具类

package com.zsp.library.recyclerview;

import android.graphics.PointF;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.LinearSmoothScroller;
import androidx.recyclerview.widget.RecyclerView;

/**
 * Created on 2018/6/28.
 *
 * @author 郑少鹏
 * @desc RecyclerViewScrollController
 */
public class RecyclerViewScrollController {
    private boolean move;
    private int index;

    /**
     * 平滑至目标位
     *
     * @param recyclerView 控件
     * @param position     位
     */
    public void smoothScrollToTargetPosition(RecyclerView recyclerView, int position) {
        LinearLayoutManager manager = (LinearLayoutManager) recyclerView.getLayoutManager();
        if (manager != null) {
            // 滑至指定位
            // 记录(第三种情况用到)
            this.index = position;
            // 当前屏幕可见头项与末项
            int firstItem = manager.findFirstVisibleItemPosition();
            int lastItem = manager.findLastVisibleItemPosition();
            // 区分
            if (position <= firstItem) {
                // 所置顶项于当前显示头项前
                recyclerView.smoothScrollToPosition(position);
            } else if (position <= lastItem) {
                // 所置顶项已于屏幕上
                int top = recyclerView.getChildAt(position - firstItem).getTop();
                recyclerView.smoothScrollBy(0, top);
            } else {
                // 所置顶项于当前显示末项后
                recyclerView.smoothScrollToPosition(position);
                move = true;
            }
            // 滑动监听
            recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                    super.onScrollStateChanged(recyclerView, newState);
                    // 此处第二次滚动
                    if (move) {
                        move = false;
                        // 所置顶项于当前屏幕位,mIndex记录所置顶于RecyclerView中位
                        int n = index - manager.findFirstVisibleItemPosition();
                        if (0 <= n && n < recyclerView.getChildCount()) {
                            // 所置顶项顶距RecyclerView顶距离
                            int top = recyclerView.getChildAt(n).getTop();
                            // 最后移动
                            recyclerView.smoothScrollBy(0, top);
                        }
                    }
                }
            });
        }
    }

    /**
     * 通滑动模式平滑至目标位
     *
     * @param recyclerView   控件
     * @param targetPosition 目标位
     * @param scrollMode     滑动模式(默SNAP_TO_ANY)
     *                       {@link LinearSmoothScroller#SNAP_TO_START}
     *                       子视图左侧或顶部对齐父视图左侧或顶部。
     *                       {@link LinearSmoothScroller#SNAP_TO_END}
     *                       子视图右侧或底部对齐父视图右侧面或底部。
     *                       {@link LinearSmoothScroller#SNAP_TO_ANY}
     *                       据子视图当前位与父布局关系定子视图从头到尾跟随否。
     *                       子视图实际于RecyclerView左侧,SNAP_TO_ANY和SNAP_TO_START无差别。
     */
    public void smoothScrollToTargetPositionWithScrollMode(RecyclerView recyclerView, int targetPosition, int scrollMode) {
        LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
        if (null == linearLayoutManager) {
            return;
        }
        LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext()) {
            @Override
            protected int getVerticalSnapPreference() {
                return scrollMode;
            }

            @Override
            public PointF computeScrollVectorForPosition(int targetPosition) {
                return linearLayoutManager.computeScrollVectorForPosition(targetPosition);
            }
        };
        recyclerView.setLayoutManager(linearLayoutManager);
        // 滑
        linearSmoothScroller.setTargetPosition(targetPosition);
        linearLayoutManager.startSmoothScroll(linearSmoothScroller);
    }

    /**
     * 条目滑至居中
     *
     * @param recyclerView 控件
     * @param position     位
     */
    public void itemScrollToCenter(RecyclerView recyclerView, int position) {
        LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
        if (linearLayoutManager != null) {
            int firstPosition = linearLayoutManager.findFirstVisibleItemPosition();
            int lastPosition = linearLayoutManager.findLastVisibleItemPosition();
            int left = recyclerView.getChildAt(position - firstPosition).getLeft();
            int right = recyclerView.getChildAt(lastPosition - position).getLeft();
            recyclerView.scrollBy((left - right) / 2, 0);
        }
    }
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

snpmyn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值