animateDpAsState увеличивает ячейку в LazyRow не равномерно, делая сдвиг в право

У меня есть LazyRow, который содержит 25 ячеек, и нужно сделать две вещи:

  1. При запуске приложения LazyRow должен автоматически прокручиваться, чтобы расположить центральную ячейку по центру экрана. Например, если у нас 25 ячеек, то ячейка №13 должна быть в центре экрана, чтобы пользователь мог прокручивать влево и вправо.
  2. Ячейка в центре должна быть в два раза больше других ячеек. Визуально ожидаемый результат выглядит так:

enter image description here

При первом запуске возникает проблема. На скриншоте выше показано ожидаемый результат (после небольшой прокрутки вручную), но при первом старте это выглядит по другому:

enter image description here

Когда центральная ячейка увеличивается, она смещает соседние ячейки справа. Это происходит потому, что анимация увеличивает размер ячейки, начиная с верхнего левого угла и расширяясь вправо.

Вопрос такой: как можно настроить анимацию так, чтобы она равномерно увеличивала центральную ячейку влево и вправо, а не только вправо как это работает сейчас.

Вот такой код:

import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.snap
import androidx.compose.animation.core.tween
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.gestures.snapping.rememberSnapFlingBehavior
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyListItemInfo
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun JustRotator(
    number: Int = 25,
    cellSize: Dp = 75.dp
) {
    val listState: LazyListState = rememberLazyListState()

    LaunchedEffect(number) {
        val idx: Int = number / 2

        listState.centerItemBy(
            idx = idx,
            animationSpec = snap()
        )
    }

    LazyRow(
        modifier = Modifier.fillMaxWidth(),
        state = listState,
        horizontalArrangement = Arrangement.Center,
        flingBehavior = rememberSnapFlingBehavior(lazyListState = listState)
    ) {
        items(count = number) { idx ->
            val isCenterItem: Boolean = listState.isItemInCenter(idx)

            val animatedSize: Dp by animateDpAsState(
                targetValue = if (isCenterItem) (cellSize * 2) else cellSize,
                animationSpec = tween(durationMillis = 300),
                label = ""
            )

            Image(
                modifier = Modifier
                    .size(animatedSize)
                    .clip(CircleShape),
                painter = painterResource(id = R.drawable.ic_profile_chooser_lock),
                contentDescription = null
            )
        }
    }
}

@Composable
fun LazyListState.isItemInCenter(
    idx: Int,
    withOffset: Int = 0
): Boolean {
    val isItemInCenter: Boolean by remember(this, idx) {
        derivedStateOf {
            val visibleItemsInfo: List<LazyListItemInfo> = layoutInfo.visibleItemsInfo
            val screenCenter: Int = (layoutInfo.viewportStartOffset + layoutInfo.viewportEndOffset) / 2

            val centeredItemIdx: Int = visibleItemsInfo.minByOrNull { itemInfo ->
                val itemCenter: Int = (itemInfo.offset + itemInfo.size / 2)
                kotlin.math.abs(screenCenter - itemCenter)
            }?.index ?: -1

            (centeredItemIdx + withOffset) == idx
        }
    }

    return isItemInCenter
}

Ответы (0 шт):