简体   繁体   中英

LazyColumn items stay in same position after some items removed

I have LazyColumn with swipe-to-delete. When I swipe an item, it is deleted by viewModel. The problem is that if I swipe the item away, the LazyColumn doesn't update the position of other items (as shown in GIF).

在此处输入图像描述

Here's my code implementation:

@ExperimentalMaterialApi
@Composable
fun Screen() {
    val livedata = viewModel.itemsLiveData.observeAsState()
    val stateList = remember { mutableStateListOf<Data>() }

    stateList.addAll(livedata.value!!)
    SwipableLazyColumn(stateList)
}

@ExperimentalMaterialApi
@Composable
fun SwipableLazyColumn(
    stateList: SnapshotStateList<Data>
) {
    LazyColumn {
        items(items = stateList) { item ->
            val dismissState = rememberDismissState()
            if (dismissState.isDismissed(EndToStart) || dismissState.isDismissed(StartToEnd)) {
                viewModel.swipeToDelete(item)
            }
            SwipeToDismiss(
                state = dismissState,
                directions = setOf(StartToEnd, EndToStart),
                dismissThresholds = {
                    FractionalThreshold(0.25f)
                },
                background = {},
                dismissContent = {
                    MyData(item)
                }
            )
        }
    }
}

I use SnapshotStateList as it's suggested here . Although I don't use swapList because it clears out all items

ViewModel :

    class MyViewModel @Inject internal constructor(
    private val itemRepository: ItemRepository
) : BaseViewModel(), LifecycleObserver {

    private val itemsList = mutableListOf<MyData>()

    private val _itemsLiveData = MutableLiveData<List<MyData>>()
    val itemsLiveData: LiveData<List<MyData>> = _itemsLiveData

    init {
        loadItems()
    }

    private fun loadItems() {
        viewModelScope.launch {
            itemRepository.getItems().collect {
                when (it) {
                    is Result.Success -> onItemsLoaded(it.data)
                    is Result.Error -> {
                        onItemsLoaded(emptyList())
                    }
                }
            }
        }
    }

    private fun onItemsLoaded(itemsList: List<MyData>) {
        itemsList.clear()
        itemsList.addAll(notifications)

        _itemsLiveData.value = if (itemsList.isNotEmpty()) {
            itemsList
        } else {
            null
        }
    }

    fun swipeToDelete(item: MyData) {
        if (itemsList.size == 0) return
        viewModelScope.launch {
            when (
                val result =
                    itemRepository.deletelItem(item)
            ) {
                is Result.Success -> {
                    onItemDeleted(item)
                }
                is Result.Error -> {
                    showSnackBar(
                        "error"
                    )
                }
            }
        }
    }

    private fun onItemDeleted(item: MyData) {
        itemsList.remove(item)
        _itemsLiveData.value = itemsList
    }
}

You need to provide key for the LazyColumn 's items .

By default, each item's state is keyed against the position of the item in the list. However, this can cause issues if the data set changes, since items which change position effectively lose any remembered state.

Example

LazyColumn {
    items(
        items = stateList,
        key = { _, listItem ->
            listItem.hashCode()
        },
    ) { item ->
        // As it is ...
    }
}

Reference

You should refresh your list inside viemodel(delete item) and return modified list right here

var tempList = itemList
ItemList.clear() 
ItemList.addAll(tempList)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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