0

I have a Custom Composable Calendar, here

I try to add a functionality to switch between month view and week view.

The point of the code is below:

LazyRow {
    items(
        key = { page -> state.getKey(page) },
    ) { page ->
        monthFiled(
            date = state.getDateByPage(page),
        )
    }
}

And here is the point:

  1. In monthView mode, state.getKey(page) return a key likes YearMonth(or page or else).
  2. In week mode, state.getKey(page) return a key likes year_weeks(or page or else).

They are different.

To ensure that the animation works correctly, I want the keys for the month view and the week view to be consistent when switching between them.

However, the relationship between month and week views is not one-to-one but one-to-many (1:5).

Is there anything that can help me switch between month and week views, as well as switch back and forth between month and week views smoothly?

Here is my minimal reproducible example

private interface View {
    val count: Int
    fun key(index: Int): Any
    fun content(index: Int): List<Int>
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun MainScreen(innerPadding: PaddingValues) {
    val list = listOf(0, 1, 2, 3, 4, 5)
    // expand
    val view1 = object : View {
        override val count: Int get() = list.size / 3
        override fun key(index: Int) = list[index * 3]
        override fun content(index: Int) = list.subList(index * 3, (index + 1) * 3)
    }
    // collapse
    val view2 = object : View {
        override val count: Int get() = list.size
        override fun key(index: Int) = list[index]
        override fun content(index: Int) = list.subList(index / 3 * 3, (index / 3 + 1) * 3)
    }

    var view: View by remember { mutableStateOf(view1) }

    val state = rememberLazyListState()
    LazyColumn(
        modifier = Modifier
            .height(100.dp)
            .clickable { view = if (view == view1) view2 else view1 },
        state = state,
        flingBehavior = rememberSnapFlingBehavior(state)
    ) {
        items(
            count = view.count,
            key = view::key,
        ) { index ->
            Row(
                modifier = Modifier.fillParentMaxHeight(),
            ) {
                view.content(index).forEach { item ->
                    AnimatedVisibility(visible = view == view1 || view.key(index) == item) {
                        Text(
                            "$item",
                            modifier = Modifier
                                .width(100.dp)
                                .fillMaxHeight()
                                .border(1.dp, Purple80),
                        )
                    }
                }
            }
        }
    }
}

It displays the list in two different ways: view1 and view2.

  1. One way is to display 3 items per row,
  2. and the other way is to display 1 item per row.

Due to key reuse,

an animation can be achieved between element0 and element0~2 for expanding and collapsing.

However, an animation cannot be achieved between element1 and element0~2.

Do you have any good suggestions?

Update at 2024/6/13

enter image description here

As you can see:

  • view1 (0,1,2) key is 0.
  • view2 (0) key is 0.

them can animate good.

In other index, the animation is wrong.(maybe contains other problems.)

I need to find a way to animate good between view1 to view2.

2

1 Answer 1

0

The keys won't help because you can only map a key of view1 to view2 but not the other way round.

Instead forget about the keys and use the LazyListState's requestScrollToItem to adjust the scroll position after you switched views:

.clickable {
    view = if (view == view1) {
        state.requestScrollToItem(state.firstVisibleItemIndex * 3)
        view2
    } else {
        state.requestScrollToItem(state.firstVisibleItemIndex / 3)
        view1
    }
},

Now the items' key parameter is not needed any more when views are switched. If you don't need the keys for anything else you can remove them entirely.

3
  • tks, It seems not works for animation. I need to animate from view1 to view2. sad. Commented Jun 13 at 6:25
  • I add a gif to show why I use the same key, to make animation fine. In your case, is that a way to keep animation find? Commented Jun 13 at 6:43
  • There are other scroll functions on state. Does any of them better fit your needs?
    – Leviathan
    Commented Jun 13 at 14:39

Not the answer you're looking for? Browse other questions tagged or ask your own question.