Fragment中ChipGroup离屏重建时如何固定方向与滚动位置?
HorizontalScrollView嵌套ChipGroup重布局异常修复方案
这两个异常是Material组件库旧版本的已知兼容问题,和滚动视图的状态恢复逻辑冲突导致,按下面的步骤改就能解决:
1. 修复布局方向LTR/RTL异常翻转
- 先把项目依赖的
com.google.android.material:material升级到1.7.0及以上稳定版,ChipGroup单Line模式下重布局翻转布局方向的问题在这个版本已经被官方修复。 - 不要等系统自动推断布局方向,在现有XML布局里给
HorizontalScrollView和ChipGroup显式加上布局方向相关属性,避免重绘时取错配置,修改后的完整XML如下:
<androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <HorizontalScrollView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="@dimen/spacing_6x" android:scrollbars="none" android:id="@+id/hs_crypto_currency" android:fillViewport="true" android:isScrollContainer="false" android:layoutDirection="locale" app:layout_constraintTop_toTopOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintBottom_toBottomOf="parent" > <com.google.android.material.chip.ChipGroup android:id="@+id/chip_group_crypto_currency_category" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layoutDirection="locale" app:singleSelection="true" app:singleLine="true" /> </HorizontalScrollView> </androidx.constraintlayout.widget.ConstraintLayout>
- 兜底处理:如果特定定制机型上还偶发翻转,在Fragment的
onViewCreated里给ChipGroup加一次全局布局监听,强制重设布局方向就行:
binding.chipGroupCryptoCurrencyCategory.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { override fun onGlobalLayout() { binding.chipGroupCryptoCurrencyCategory.layoutDirection = View.LAYOUT_DIRECTION_LOCALE binding.chipGroupCryptoCurrencyCategory.viewTreeObserver.removeOnGlobalLayoutListener(this) } })
2. 修复视图回显时自动滚动到最后一个Chip的问题
这个问题是两个逻辑冲突导致的:一是HorizontalScrollView在子View重新布局时,会自动滚动到获取焦点的子项位置;二是ChipGroup单选中模式下默认会在重绘时尝试把选中项滚到可视区域,两个逻辑叠在一起就会触发错误跳转。
按下面的方式改代码逻辑:
- 所有动态Chip添加完成、设置完默认选中项后,主动把滚动视图的位置重置到初始位置:
// 替换成你项目里对应的视图绑定/ findViewById写法 binding.hsCryptoCurrency.post { binding.hsCryptoCurrency.scrollTo(0, 0) }
- 给ChipGroup加选中状态监听时,过滤掉视图不可见、未附着到窗口的场景,避免后台状态下触发错误滚动。需要滚动到选中项的时候手动控制滚动位置,替代组件自带的默认逻辑:
binding.chipGroupCryptoCurrencyCategory.setOnCheckedStateChangeListener { group, checkedIds -> // 视图没加载完成的时候直接返回,不处理任何逻辑 if (!group.isAttachedToWindow || group.visibility != View.VISIBLE) return@setOnCheckedStateChangeListener val selectedChipId = checkedIds.firstOrNull() ?: return@setOnCheckedStateChangeListener // 这里写你原有的业务逻辑,比如根据选中的分类加载对应数据 val selectedChip = group.findViewById<Chip>(selectedChipId) // 手动控制选中项的滚动位置,留2倍间距作为边距,避免Chip贴边 selectedChip?.let { val offset = resources.getDimensionPixelOffset(R.dimen.spacing_2x) binding.hsCryptoCurrency.smoothScrollTo(it.left - offset, 0) } }
内容的提问来源于stack exchange,提问作者WhoisAbel
相关产品推荐
相关产品推荐

