RecyclerView + SnapHelper 滚动差异问题

问题概述:

使用 scrollToPosition(position) 跳转到 倒数第二个 item ,配合自定义的 CustomSnapHelper无法成功吸附到左边 。 使用 smoothScrollToPosition(position) 则一切正常。

kotlin 复制代码
class CustomSnapHelper : PagerSnapHelper() {
    private var mHorizontalHelper: OrientationHelper? = null

    override fun calculateDistanceToFinalSnap(layoutManager: RecyclerView.LayoutManager, targetView: View): IntArray {
        val out = IntArray(2)
        // 判断支持水平滚动,修改水平方向的位置,是修改的out[0]的值
        if (layoutManager.canScrollHorizontally()) {
            out[0] = distanceToStart(targetView, getHorizontalHelper(layoutManager))
        } else {
            out[0] = 0
        }
        return out
    }

    private fun distanceToStart(targetView: View, helper: OrientationHelper): Int {
        return helper.getDecoratedStart(targetView) - helper.startAfterPadding
    }

    override fun findSnapView(layoutManager: RecyclerView.LayoutManager): View? {
        return findStartView(layoutManager, getHorizontalHelper(layoutManager))
    }

    private fun findStartView(layoutManager: RecyclerView.LayoutManager, helper: OrientationHelper): View? {
        return super.findSnapView(layoutManager)
    }

    private fun getHorizontalHelper(layoutManager: RecyclerView.LayoutManager): OrientationHelper {
        if (mHorizontalHelper == null) {
            mHorizontalHelper = OrientationHelper.createHorizontalHelper(layoutManager)
        }
        return mHorizontalHelper!!
    }
}

关键原因:是否触发 findSnapView

方法 会触发滚动动画 会触发 LayoutManager layout SnapHelper 可介入定位?
scrollToPosition(position) 否(瞬间跳转) 只 layout 当前页及之后几项 不会立即触发 SnapHelper 定位
smoothScrollToPosition(position) 连续 layout 滑动中的 item 会触发 SnapHelper 计算并吸附

解决方案: 在滚动之后,手动触发它吸附目标 view 到左侧:

kotlin 复制代码
/**
 * 强制触发 SnapHelper 吸附,确保目标 Item 吸附到左边
 *
 * 用于 scrollToPosition() 之后,确保 item 能平滑对齐到左边(通常结合 CustomSnapHelper 使用)
 *
 * @param recyclerView 绑定了自定义 CustomSnapHelper 的 RecyclerView
 */
fun forceSnapToStartAfterScroll(recyclerView: RecyclerView) {
    // 尝试获取当前 RecyclerView 使用的 SnapHelper(这里是自定义的 CustomSnapHelper)
    val snapHelper = recyclerView.onFlingListener as? CustomSnapHelper
    Logger.e("触发 SnapHelper 对齐 snapHelper = $snapHelper")

    // 如果有设置 SnapHelper,则手动触发一次吸附逻辑
    if (snapHelper != null) {
        recyclerView.post {
            val layoutManager = recyclerView.layoutManager ?: return@post

            // 找到当前需要吸附的目标 View
            val snapView = snapHelper.findSnapView(layoutManager) ?: return@post

            // 计算从当前位置到最终吸附位置所需的平移距离(x/y)
            val distance = snapHelper.calculateDistanceToFinalSnap(layoutManager, snapView)

            // 如果需要移动(距离非0),则平滑滚动使其吸附
            if (distance != null && (distance[0] != 0 || distance[1] != 0)) {
                recyclerView.smoothScrollBy(distance[0], distance[1])
            }
        }
    }
}
相关推荐
千里马学框架2 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台2 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone2 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc2 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo2 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077002 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼2 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone2 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen2 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone2 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui