简体   繁体   English

使用滚动位置重置更新 Jetpack Compose 列表

[英]Update Jetpack Compose list with scroll position reset

In my app I have list of items shown with LazyColumn.在我的应用程序中,我使用 LazyColumn 显示了项目列表。 My list can update fields and sometime reorder items.我的列表可以更新字段,有时还可以重新排序项目。 Whenever I have reorder of items I need to show list with first item at the top.每当我对项目重新排序时,我都需要在顶部显示第一个项目的列表。 I came up with setup like the one below.我想出了如下设置。 List scrolls to the top only on the first reorder event.列表仅在第一个重新排序事件时滚动到顶部。 On consecutive list update with reorder = true , my list not scrolling to the top.在使用reorder = true连续更新列表时,我的列表不会滚动到顶部。 What is the better approach in Compose to reset list scroll position (or even force rebuilding compose list) by sending state from ViewModel? Compose 中通过从 ViewModel 发送状态来重置列表滚动位置(甚至强制重建撰写列表)的更好方法是什么?

class ViewItemsState(val items: List<ViewItem>, val scrollToTop: Boolean)

class ExampleViewModel() : ViewModel() {
    
    var itemsLiveData = MutableLiveData<ViewItemsState>()

}

@Composable
fun ExampleScreen(viewModel: ExampleViewModel = viewModel()) {

    val itemState  by viewModel.itemsLiveData.observeAsState()
    val coroutineScope = rememberCoroutineScope()
    val listState = rememberLazyListState()

    if (itemState.scrollToTop) {
        LaunchedEffect(coroutineScope) {
            Log.e("TAG", "TopCoinsScreen: scrollToTop" )
            listState.scrollToItem(0)
        }
    }

    LazyColumn(state = listState) {
        items(itemState.items) { item ->
            ItemCompose(
                item.name,
                item.value
            )
        }
    }
}

Recomposition is triggered only when a state changes.仅当状态发生变化时才会触发重组。

Two things to fix in this,有两件事要解决这个问题,

  1. Reset scrollToTop to false once scrolling completes.滚动完成后将scrollToTop重置为false
  2. Store scrollToTop in the view model as a MutableState , LiveData , Flow , or any other reactive element.scrollToTop作为MutableStateLiveDataFlow或任何其他反应式元素存储在视图模型中。

Currently scrollToTop is stored as a boolean in a data class object.目前scrollToTop在数据类对象中存储为布尔值。 Resetting the value will not trigger a Composable recomposition.重置该值不会触发可组合重组。

Example code with sample data,带有示例数据的示例代码,

class ViewItemsState(
    val items: List<String>,
)

class ExampleViewModel : ViewModel() {
    private var _itemsLiveData =
        MutableLiveData(
            ViewItemsState(
                items = Array(20) {
                    it.toString()
                }.toList(),
            )
        )
    val itemsLiveData: LiveData<ViewItemsState>
        get() = _itemsLiveData

    private var _scrollToTop = MutableLiveData(false)
    val scrollToTop: LiveData<Boolean>
        get() = _scrollToTop

    fun updateScrollToTop(scroll: Boolean) {
        _scrollToTop.postValue(scroll)
    }
}

@Composable
fun ExampleScreen(
    viewModel: ExampleViewModel = ExampleViewModel(),
) {
    val itemState by viewModel.itemsLiveData.observeAsState()
    val scrollToTop by viewModel.scrollToTop.observeAsState()
    val listState = rememberLazyListState()

    LaunchedEffect(
        key1 = scrollToTop,
    ) {
        if (scrollToTop == true) {
            listState.scrollToItem(0)
            viewModel.updateScrollToTop(false)
        }
    }

    Column {
        LazyColumn(
            state = listState,
            modifier = Modifier.weight(1f),
        ) {
            items(itemState?.items.orEmpty()) { item ->
                Text(
                    text = item,
                    modifier = Modifier.padding(16.dp),
                )
            }
        }
        Button(
            onClick = {
                viewModel.updateScrollToTop(true)
            },
        ) {
            Text(text = "Scroll")
        }
    }
}

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

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