简体   繁体   English

记住 LazyColumn Scroll Position - Jetpack Compose

[英]Remember LazyColumn Scroll Position - Jetpack Compose

I'm trying to save/remember LazyColumn scroll position when I navigate away from one composable screen to another.当我从一个可组合屏幕导航到另一个时,我试图保存/记住 LazyColumn 滚动条 position。 Even if I pass a rememberLazyListState to a LazyColumn the scroll position is not saved after I get back to my first composable screen.即使我将 rememberLazyListState 传递给 LazyColumn,在我返回第一个可组合屏幕后,滚动条 position 也不会保存。 Can someone help me out?有人可以帮我吗?

@ExperimentalMaterialApi
@Composable
fun DisplayTasks(
    tasks: List<Task>,
    navigateToTaskScreen: (Int) -> Unit
) {
    val listState = rememberLazyListState()

    LazyColumn(state = listState) {
        itemsIndexed(
            items = tasks,
            key = { _, task ->
                task.id
            }
        ) { _, task ->
            LazyColumnItem(
                toDoTask = task,
                navigateToTaskScreen = navigateToTaskScreen
            )
        }
    }
}
/**
 * Static field, contains all scroll values
 */
private val SaveMap = mutableMapOf<String, KeyParams>()

private data class KeyParams(
    val params: String = "",
    val index: Int,
    val scrollOffset: Int
)

/**
 * Save scroll state on all time.
 * @param key value for comparing screen
 * @param params arguments for find different between equals screen
 * @param initialFirstVisibleItemIndex see [LazyListState.firstVisibleItemIndex]
 * @param initialFirstVisibleItemScrollOffset see [LazyListState.firstVisibleItemScrollOffset]
 */
@Composable
fun rememberForeverLazyListState(
    key: String,
    params: String = "",
    initialFirstVisibleItemIndex: Int = 0,
    initialFirstVisibleItemScrollOffset: Int = 0
): LazyListState {
    val scrollState = rememberSaveable(saver = LazyListState.Saver) {
        var savedValue = SaveMap[key]
        if (savedValue?.params != params) savedValue = null
        val savedIndex = savedValue?.index ?: initialFirstVisibleItemIndex
        val savedOffset = savedValue?.scrollOffset ?: initialFirstVisibleItemScrollOffset
        LazyListState(
            savedIndex,
            savedOffset
        )
    }
    DisposableEffect(Unit) {
        onDispose {
            val lastIndex = scrollState.firstVisibleItemIndex
            val lastOffset = scrollState.firstVisibleItemScrollOffset
            SaveMap[key] = KeyParams(params, lastIndex, lastOffset)
        }
    }
    return scrollState
}

example of use使用示例

LazyColumn(
    state = rememberForeverLazyListState(key = "Overview")
)

Well if you literally want to save it, you must store it is something like a viewmodel where it remains preserved.好吧,如果您真的想保存它,则必须将其存储为类似视图模型的东西,并且它仍然保留下来。 The remember ed stuff only lasts till the Composable gets destroyed. remember东西只持续到可组合被销毁。 If you navigate to another screen, the previous Composables are destroyed and along with them, the scroll state如果您导航到另一个屏幕,则先前的 Composable 将被销毁,并且滚动状态也会随之销毁

@Composable
fun persistedScrollState(viewModel: ParentViewModel): ScrollState {
    val scrollState = rememberScrollState(viewModel.scrollPosition)
    DisposableEffect(key1 = null) {
        onDispose {
            viewModel.scrollPosition = scrollState.value
        }
    }
    return scrollState
}

Above I defined a helper function to persist scroll state when a composable is disposed of.上面我定义了一个辅助函数,用于在处理可组合项时保持滚动状态。 All that is needed is a ViewModel with a scroll position variable.所需要的只是一个带有滚动位置变量的 ViewModel。

Hope this helps someone!希望这对某人有帮助!

Column(modifier = Modifier
   .fillMaxSize()
   .verticalScroll(
       persistedScrollState(viewModel = viewModel)
   ) {
   //Your content here
}
@Composable
fun persistedLazyScrollState(viewModel: YourViewModel): LazyListState {
        val scrollState = rememberLazyListState(viewModel.firstVisibleItemIdx, viewModel.firstVisibleItemOffset)
        DisposableEffect(key1 = null) {
            onDispose {
                viewModel.firstVisibleItemIdx = scrollState.firstVisibleItemIndex
                viewModel.firstVisibleItemOffset = scrollState.firstVisibleItemScrollOffset
            }
        }
        return scrollState
    }
}

Above I defined a helper function to persist scroll state when a composable is disposed of.在上面,我定义了一个帮助程序 function 以在处置可组合项时保留滚动条 state。 All that is needed is a ViewModel with variables for firstVisibleItemIdx and firstVisibleItemOffet.所需要的只是一个带有 firstVisibleItemIdx 和 firstVisibleItemOffet 变量的 ViewModel。

Column(modifier = Modifier
   .fillMaxSize()
   .verticalScroll(
       persistedScrollState(viewModel = viewModel)
   ) {
   //Your content here
}

The LazyColumn should save scroll position out of the box when navigating to next screen.导航到下一个屏幕时, LazyColumn应该立即保存滚动条 position。 If it doesn't work, this may be a bug described here ( issue tracker ).如果它不起作用,这可能是此处描述的错误(问题跟踪器)。 Basically check if the list becomes empty when changing screens, eg because you observe a cold Flow or LiveData (so the initial value is used).基本上检查列表是否在更改屏幕时变空,例如,因为您观察到冷流或 LiveData(因此使用初始值)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM