Как избежать ненужных рекомпозиций в LazyRow

У меня есть LazyRow с несколькими ячейками, и он отслеживает элемент, который находится в центре экрана. Проблема в том, что для отслеживания этого центрального элемента я использую State, и каждый раз, когда этот State обновляется, происходит рекомпозиция. Я заметил в LayoutInspector, что ячейки в LazyRow постоянно обновляются при прокрутке влево или вправо. Этого не происходит, если я закомментирую отслеживание State.

Вопрос: как избежать ненужных рекомпозиций?

Вот код:

import androidx.compose.animation.core.animateDpAsState
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.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()

    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 шт):