animateDpAsState увеличивает ячейку в LazyRow не равномерно, делая сдвиг в право
У меня есть LazyRow, который содержит 25 ячеек, и нужно сделать две вещи:
- При запуске приложения LazyRow должен автоматически прокручиваться, чтобы расположить центральную ячейку по центру экрана. Например, если у нас 25 ячеек, то ячейка №13 должна быть в центре экрана, чтобы пользователь мог прокручивать влево и вправо.
- Ячейка в центре должна быть в два раза больше других ячеек. Визуально ожидаемый результат выглядит так:
При первом запуске возникает проблема. На скриншоте выше показано ожидаемый результат (после небольшой прокрутки вручную), но при первом старте это выглядит по другому:
Когда центральная ячейка увеличивается, она смещает соседние ячейки справа. Это происходит потому, что анимация увеличивает размер ячейки, начиная с верхнего левого угла и расширяясь вправо.
Вопрос такой: как можно настроить анимацию так, чтобы она равномерно увеличивала центральную ячейку влево и вправо, а не только вправо как это работает сейчас.
Вот такой код:
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
}