如何仅在向上滚动时为CollapsingToolbarLayout启用吸附滚动
实现仅向上滚动时CollapsingToolbar的吸附滚动效果
我需要实现仅在向上滚动时为AppBarLayout中的CollapsingToolbar启用吸附滚动:
- 向上滚动到应用栏内容的50%位置时,自动展开或折叠工具栏
- 向下滚动时,CollapsingToolbarLayout不触发吸附行为,保持正常滚动
以下是我目前尝试的代码:
appBarLayout.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset -> val viewHeight = abs(appBarLayout.totalScrollRange) - abs(verticalOffset) val viewingPercentage = viewHeight.toFloat() / abs(appBarLayout.totalScrollRange).toFloat() if(isToolBarHalfScrolled && viewingPercentage >= .5f){ isToolBarHalfScrolled = false val params: AppBarLayout.LayoutParams = collapsing_toolbar.layoutParams as AppBarLayout.LayoutParams params.scrollFlags = SCROLL_FLAG_SNAP or SCROLL_FLAG_SCROLL collapsing_toolbar.layoutParams = params } else if(!isToolBarHalfScrolled && viewingPercentage < .5f){ isToolBarHalfScrolled = true val params: AppBarLayout.LayoutParams = collapsing_toolbar.layoutParams as AppBarLayout.LayoutParams params.scrollFlags = SCROLL_FLAG_SCROLL collapsing_toolbar.layoutParams = params } })
问题分析
现有代码的核心缺陷是未判断滚动方向,仅通过当前滚动百分比切换scrollFlags,无法区分向上/向下滚动场景,导致吸附逻辑不符合预期。
正确实现方案
我们需要记录上一次的垂直偏移量来判断滚动方向,再结合滚动百分比动态调整scrollFlags:
// 记录上一次的垂直偏移量,初始值设为0 private var lastVerticalOffset = 0 // 标记当前是否启用了吸附 private var isSnapEnabled = false // 初始化AppBarLayout滚动监听 appBarLayout.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset -> val totalScrollRange = appBarLayout.totalScrollRange if (totalScrollRange == 0) return@OnOffsetChangedListener // 计算当前滚动百分比:0=完全折叠,1=完全展开 val scrollPercentage = abs(verticalOffset).toFloat() / totalScrollRange.toFloat() // 判断滚动方向:verticalOffset为负数,值越小表示向上滚动(折叠程度增加) val isScrollingUp = verticalOffset < lastVerticalOffset // 更新上一次偏移量 lastVerticalOffset = verticalOffset // 仅在向上滚动时处理吸附逻辑 if (isScrollingUp) { // 滚动超过50%且未启用吸附时,开启吸附 if (scrollPercentage >= 0.5f && !isSnapEnabled) { updateCollapsingToolbarScrollFlags(true) isSnapEnabled = true } // 滚动回到50%以内且已启用吸附时,关闭吸附 else if (scrollPercentage < 0.5f && isSnapEnabled) { updateCollapsingToolbarScrollFlags(false) isSnapEnabled = false } } else { // 向下滚动时强制关闭吸附,保持正常滚动 if (isSnapEnabled) { updateCollapsingToolbarScrollFlags(false) isSnapEnabled = false } } }) // 封装修改scrollFlags的方法,避免重复代码 private fun updateCollapsingToolbarScrollFlags(enableSnap: Boolean) { val params = collapsing_toolbar.layoutParams as AppBarLayout.LayoutParams params.scrollFlags = if (enableSnap) { AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL or AppBarLayout.LayoutParams.SCROLL_FLAG_SNAP } else { AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL } collapsing_toolbar.layoutParams = params }
关键点说明
- 滚动方向判断:通过对比当前与上一次的
verticalOffset值,verticalOffset为负数,值越小(更负)表示向上滚动,折叠程度增加。 - 状态标记:用
isSnapEnabled标记当前吸附状态,避免频繁重复修改LayoutParams,提升性能。 - 逻辑封装:将修改
scrollFlags的逻辑单独封装,提升代码可读性和可维护性。
内容的提问来源于stack exchange,提问作者Shafayat Tiger IT
相关产品推荐
相关产品推荐

