You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Jetpack Compose的Row组件中始终居中选中元素

让选中Item始终在Row组件内居中的实现方案

要实现点击任意Item后,该Item自动滚动到Row的中心位置并保持居中,可通过以下方式实现:

完整修改代码

data class Balance(
    val amount: String,
    val isSelected: Boolean
)

@Composable
fun Test() {
    val scrollState = rememberScrollState()
    val coroutineScope = rememberCoroutineScope()
    val list = remember {
        mutableStateListOf(
            Balance("$342.23", false),
            Balance("€23,342.23", false),
            Balance("£9,934.30", false),
            Balance("BGN 543.43", false),
            Balance("BLR 43.35", true),
            Balance("HUN 492.35", false),
            Balance("JPY 5326", false)
        )
    }
    val paddingHorizontal = 50.dp
    val parentWidth = 400.dp
    val itemPositions = remember { mutableMapOf<Int, IntOffset>() }
    val density = LocalDensity.current
    val parentWidthPx = density.run { parentWidth.toPx() }
    val paddingHorizontalPx = density.run { paddingHorizontal.toPx() }
    // 计算Row的实际可显示宽度(扣除左右内边距)
    val displayWidthPx = parentWidthPx - 2 * paddingHorizontalPx

    Row(
        horizontalArrangement = Arrangement.Center,
        verticalAlignment = Alignment.Bottom,
        modifier = Modifier
            .padding(horizontal = paddingHorizontal)
            .width(parentWidth)
            .wrapContentHeight()
            .horizontalScroll(scrollState)
    ) {
        list.forEachIndexed { i, item ->
            val (amount, isSelected) = item
            Text(
                text = amount,
                color = if (isSelected) Color.Red else Color.Red.copy(alpha = 0.2f),
                fontSize = 15.sp,
                modifier = Modifier
                    .padding(horizontal = 10.dp)
                    .onGloballyPositioned { coordinates ->
                        // 记录每个Item的全局位置坐标
                        itemPositions[i] = coordinates.positionInRoot()
                    }
                    .clickable {
                        // 更新选中状态
                        val prevSelectedIndex = list.indexOfFirst { it.isSelected }
                        list[i] = list[i].copy(isSelected = true)
                        list[prevSelectedIndex] = list[prevSelectedIndex].copy(isSelected = false)

                        // 计算并执行滚动,让选中项居中
                        coroutineScope.launch {
                            itemPositions[i]?.let { position ->
                                val itemCenterX = position.x + coordinates.size.width / 2
                                // 目标滚动偏移:选中项中心 - 内边距 - 可显示宽度的一半
                                val targetOffset = itemCenterX - (paddingHorizontalPx + displayWidthPx / 2)
                                scrollState.animateScrollTo(targetOffset.toInt())
                            }
                        }
                    }
            )
        }
    }
}

核心实现逻辑

  1. 记录Item位置:通过onGloballyPositioned获取每个Text组件的全局坐标,存储到itemPositions映射中,用于后续计算滚动偏移。
  2. 计算滚动目标:选中项切换时,计算选中项的中心X坐标,结合Row的内边距和可显示宽度,算出需要滚动的目标偏移量,确保选中项刚好位于Row的视觉中心。
  3. 平滑滚动触发:借助rememberCoroutineScope启动协程,调用scrollState.animateScrollTo实现平滑滚动到目标位置。

效果说明

点击任意金额项后,该Item会自动平滑滚动到Row的中心位置,始终保持居中显示。

内容的提问来源于stack exchange,提问作者slaviboy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 04:33:20