Wear OS Compose onResume时ScalingLazyColumn滚动到顶部实现方案
解决方案
核心思路是把「回到页面触发onResume」和「页面重组」两个场景的逻辑拆开处理:
- 列表滚动状态用
rememberScalingLazyListState()正常持有,重组时Compose会自动缓存该状态,不会重置位置 - 单独监听页面生命周期,仅在收到
ON_RESUME事件时主动触发列表滚动到顶部,重组时不做任何列表位置干预
具体实现代码
直接使用Compose官方自带的生命周期、协程API即可,不需要引入第三方库,修改后的代码如下:
import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver import kotlinx.coroutines.launch @Composable fun WearApp(weatherVM: WeatherViewModel, application: Application) { WearAppTheme { val weather = weatherVM.weather.observeAsState(initial = null) val listState = rememberScalingLazyListState() val coroutineScope = rememberCoroutineScope() // 仅监听onResume生命周期事件,触发回到页面的滚动归位 val lifecycleOwner = LocalLifecycleOwner.current DisposableEffect(lifecycleOwner) { val observer = LifecycleEventObserver { _, event -> if (event == Lifecycle.Event.ON_RESUME) { coroutineScope.launch { // 需要平滑滚动用animateScrollToItem,不需要动画直接替换为scrollToItem(0) listState.animateScrollToItem(index = 0, scrollOffset = 0) } } } lifecycleOwner.lifecycle.addObserver(observer) onDispose { lifecycleOwner.lifecycle.removeObserver(observer) } } Scaffold( positionIndicator = { PositionIndicator( scalingLazyListState = listState ) } ) { ScalingLazyColumn( modifier = Modifier.fillMaxSize(), autoCentering = AutoCenteringParams(itemIndex = 0), state = listState ) { item { // 原有首屏/列表项内容保持不变 } item { // 原有列表项内容保持不变 } // 其余原有列表逻辑无需修改 } } } }
避坑说明
- 不要给
rememberScalingLazyListState()传入任何和页面状态(比如weather返回值)绑定的key,否则对应状态变化触发重组时,列表状态会被重新初始化,直接丢失滚动位置 - 滚动方法必须放在协程中调用,
animateScrollToItem/scrollToItem都是挂起函数,直接在主线程同步调用会抛异常 - 不要在Composable函数的非副作用域里直接调用滚动方法,否则每次重组都会触发滚动归位,不符合需求
内容的提问来源于stack exchange,提问作者GDefender
相关产品推荐
相关产品推荐

