HorizontalPageIndicator滑动时三次重组是否正常?代码是否有误?
滑动HorizontalPager时HorizontalPageIndicator触发3次重组的原因及优化
这种现象属于正常状态更新范围内的情况,但你的代码写法存在可优化点,能减少不必要的重组次数,具体说明如下:
为什么会触发多次重组?
滑动过程中,PagerState的核心状态会持续更新:
- 滑动开始时,
currentPageOffsetFraction从0开始变化,触发第一次状态更新; - 滑动过半切换页面时,
currentPage数值变化,触发第二次更新; - 滑动结束时,
currentPageOffsetFraction回归0,触发第三次更新。
但你的代码里,每次derivedStateOf计算都会创建匿名的PageIndicatorState对象——Compose判断重组的依据是参数的引用或值是否变化,匿名对象每次都是新实例,哪怕内部属性值没变化,也会被判定为参数更新,导致HorizontalPageIndicator额外触发重组。
优化方案:使用稳定的状态实现
把匿名的PageIndicatorState替换为稳定的数据类实现,data class的equals方法会基于属性值判断是否相等,只有当属性真正变化时,才会生成新实例,避免不必要的重组。
优化后的代码:
// 定义稳定的PageIndicatorState实现 data class DefaultPageIndicatorState( override val pageCount: Int, override val pageOffset: Float, override val selectedPage: Int ) : PageIndicatorState @Composable fun HouseholdScreen( isLoading: Boolean, households: List<Household>, clickOnDevice: (id: String) -> Unit ) { val pagerState = rememberPagerState { households.size } val pageIndicatorState = remember { derivedStateOf { DefaultPageIndicatorState( pageCount = pagerState.pageCount, pageOffset = pagerState.currentPageOffsetFraction, selectedPage = pagerState.currentPage ) } } HorizontalPager( state = pagerState, key = { households[it].id } ) { page -> HouseholdScreen( isLoading = isLoading, household = households[page] ) { deviceId -> clickOnDevice(deviceId) } } HorizontalPageIndicator( pageIndicatorState = pageIndicatorState.value, modifier = Modifier.padding(4.dp) ) }
优化后的效果
优化后,HorizontalPageIndicator只会在pageCount、currentPageOffsetFraction或currentPage真正变化时重组,滑动过程中必要的动画更新仍会保留,但不会因为对象引用变化触发额外重组。
内容的提问来源于stack exchange,提问作者pie
相关产品推荐
相关产品推荐

