最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

android - How to add animation when removing an item in HorizontalPager in Jetpack Compose - Stack Overflow

programmeradmin6浏览0评论

I have an HorizontalPager in Compose and users are able to remove any item of Pager. When the user removes any item i want other elements move to empty place with an animation.

This is actually a default animation for RecylerView(ListAdapter) or even LazyColumn uses animateItem to manage that or with deprecated name animateItemPlacement.

I'm wondering how can I achieve the same concept in HorizontalPager?

@Composable
fun HomePageBanner(
    bannerList: List<BannerUIModel>,
    modifier: Modifier = Modifier,
    onButtonClicked: (index: Int) -> Unit = {},
    onItemRemoved: (index: Int) -> Unit = {},
) {
    val pageCount = bannerList.size
    val pagerState = rememberPagerState(pageCount = { pageCount })
    HorizontalPager(
        state = pagerState,
        modifier = modifier,
        contentPadding = PaddingValues(start = 16.dp, end = 12.dp),
        pageSpacing = 0.dp,
    ) { index ->
        val banner = bannerList[index]
        BannerCardItem(
            bannerItem = banner,
            modifier = Modifier.fillMaxWidth().padding(12.dp),
            onButtonClicked = { onButtonClicked(index) },
            onItemRemoved = {
                // When this is called, the item will be removed 
                // and HomePageBanner will be called with the new list
                onItemRemoved(index)
            },
        )
    }
}

I have an HorizontalPager in Compose and users are able to remove any item of Pager. When the user removes any item i want other elements move to empty place with an animation.

This is actually a default animation for RecylerView(ListAdapter) or even LazyColumn uses animateItem to manage that or with deprecated name animateItemPlacement.

I'm wondering how can I achieve the same concept in HorizontalPager?

@Composable
fun HomePageBanner(
    bannerList: List<BannerUIModel>,
    modifier: Modifier = Modifier,
    onButtonClicked: (index: Int) -> Unit = {},
    onItemRemoved: (index: Int) -> Unit = {},
) {
    val pageCount = bannerList.size
    val pagerState = rememberPagerState(pageCount = { pageCount })
    HorizontalPager(
        state = pagerState,
        modifier = modifier,
        contentPadding = PaddingValues(start = 16.dp, end = 12.dp),
        pageSpacing = 0.dp,
    ) { index ->
        val banner = bannerList[index]
        BannerCardItem(
            bannerItem = banner,
            modifier = Modifier.fillMaxWidth().padding(12.dp),
            onButtonClicked = { onButtonClicked(index) },
            onItemRemoved = {
                // When this is called, the item will be removed 
                // and HomePageBanner will be called with the new list
                onItemRemoved(index)
            },
        )
    }
}
Share edited Nov 29, 2024 at 17:51 Umut Tekin asked Nov 29, 2024 at 14:23 Umut TekinUmut Tekin 2582 silver badges17 bronze badges 2
  • Please edit your question and provide the code you have so far. – tyg Commented Nov 29, 2024 at 14:29
  • Actually this question is independent of code because I am looking for the equivalent of the default animation used in Lists in the Android world for Compose Pager. I'll still share the basic implementation of the Pager. – Umut Tekin Commented Nov 29, 2024 at 17:47
Add a comment  | 

1 Answer 1

Reset to default 4

Modifier.animateItem() is a scoped Modifier defined in LazyItemScope. There is no default PagerScope modifier, actually nothing in PagerScope yet. You can open a feature request for Pager as well.

/**
 * Receiver scope for [Pager].
 * Note: This is empty now, but we may add new members in the future if needed.
 */
sealed interface PagerScope

internal object PagerScopeImpl : PagerScope

But You can apply snapping behavior to LazyRow/Column you can snap as Pager does and use Modifer.animateItem()

Animating LazyRow item change

Data class must have unique keys for matching which items to animate for placement, which ones for appear and which ones for disappear and must be used inside key = {item-> item.id}.

data class MyData(val id: String = UUID.randomUUID().toString(), val value: Int)

class MyViewModel : ViewModel() {
    val list =
        mutableStateListOf<MyData>().apply {
            repeat(6) {
                add(
                    MyData(value = it)
                )
            }
        }

    fun removeItem(index: Int) {
        list.removeAt(index)
    }
}


@Preview
@Composable
fun LazyRowSnapAndDeleteAnimation() {

    val viewModel = remember {
        MyViewModel()
    }

    val lazyListState = rememberLazyListState()
    Column(
        modifier = Modifier.fillMaxSize().background(backgroundColor).padding(vertical = 32.dp)
    ) {

        val list = viewModel.list

        LazyRow(
            modifier = Modifier.fillMaxSize(),
            contentPadding = PaddingValues(start = 16.dp, end = 12.dp),
            flingBehavior = rememberSnapFlingBehavior(lazyListState, snapPosition = SnapPosition.Start),
            state = lazyListState
        ) {

            itemsIndexed(
                items = list,
                key = { _, item ->
                    item.id
                }
            ) { page, item ->
                Column(
                    modifier = Modifier
                        .animateItem()
                        .fillParentMaxWidth()
                        .height(200.dp)
                        .shadow(2.dp, RoundedCornerShape(16.dp))
                        .background(Color.White)
                        .padding(32.dp)
                ) {
                    Text("Item")

                    Button(
                        modifier = Modifier.fillMaxWidth(),
                        onClick = {
                            viewModel.removeItem(page)
                        }
                    ) {
                        Text("Remove ${item.value}")
                    }
                }
            }
        }
    }
}

Animating HorizontalPager item change

If using LazyRow is out of question you can write a Modifier that does that but it's not easy and there are several cases to handle since we are building similar Modifier as animateItem manually.

Basically, you need to set Modifier.layout with layer, also HorizontalPager has fixed page size, do not let items shrink you need to handle item scrolling. In addition, in your case, you should also handle cases for previous and next items because of content padding makes them partially visible.

Step1 - Using a flag to signal animation

When manually animating deleted items first step is using a flag to make them eligible for animation then after animation finishes because removin items list removes them from composition, so they must be removed at the end.

Or you can use another list to compare as LazyList does to check which items to change position, which items to disappear and which ones to appear.

Updated ViewModel and data like this

data class MyData(val id: String = UUID.randomUUID().toString(), val value: Int, val isAlive: Boolean = true)

class MyViewModel : ViewModel() {
    val list =
        mutableStateListOf<MyData>().apply {
            repeat(6) {
                add(
                    MyData(value = it)
                )
            }
        }

    fun updateStatus(index: Int) {
        val newItem = list[index].copy(isAlive = false)
        list[index] = newItem
        println("Update Status: $index")
    }

    fun removeItem(index: Int) {
        println("
发布评论

评论列表(0)

  1. 暂无评论