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

Jetpack Compose:如何定义依赖组件尺寸的swipeable锚点?

如何定义依赖组件自身尺寸的Swipeable锚点?

官方提供的swipeable示例使用硬编码值定义锚点,无法适配组件自身的动态尺寸。以下是基于稳定版swipeable(实验性API)的解决方案,无需依赖仍处于Alpha阶段的AnchoredDraggable:

方案一:使用onSizeChanged动态获取尺寸

通过onSizeChanged回调获取组件的实际布局尺寸,再动态更新锚点映射:

@OptIn(ExperimentalMaterialApi::class)
@Composable
private fun DynamicSwipeableSample() {
    val swipeableState = rememberSwipeableState(0)
    // 用可变状态保存锚点,支持动态更新
    val anchors = remember { mutableStateMapOf<Float, Int>() }
    // 滑块固定尺寸(可根据需求调整)
    val squareSize = 48.dp
    val squareSizePx = with(LocalDensity.current) { squareSize.toPx() }

    Box(
        modifier = Modifier
            .background(Color.LightGray)
            // 监听组件尺寸变化,更新锚点
            .onSizeChanged { containerSize ->
                val maxOffset = (containerSize.width - squareSizePx).coerceAtLeast(0f)
                anchors.apply {
                    clear()
                    put(0f, 0)
                    put(maxOffset, 1)
                }
            }
            // 锚点初始化完成后再应用swipeable修饰符
            .then(
                if (anchors.isNotEmpty()) {
                    Modifier.swipeable(
                        state = swipeableState,
                        anchors = anchors,
                        thresholds = { _, _ -> FractionalThreshold(0.3f) },
                        orientation = Orientation.Horizontal
                    )
                } else {
                    Modifier
                }
            )
    ) {
        // 可滑动的子组件
        Box(
            modifier = Modifier
                .size(squareSize)
                .background(Color.Blue)
                .offset { IntOffset(swipeableState.offset.value.roundToInt(), 0) }
        )
    }
}

关键说明:

  • 用mutableStateMapOf存储锚点,确保尺寸变化时Compose能自动重组并更新swipeable配置
  • coerceAtLeast(0f)处理容器尺寸小于滑块尺寸的边界情况,避免出现负偏移
  • 通过then条件应用swipeable,防止初始锚点为空时触发异常

方案二:使用Layout组件精准控制布局

如果需要更精细的布局尺寸控制,可以直接使用Layout组件获取容器和子组件的尺寸:

@OptIn(ExperimentalMaterialApi::class)
@Composable
private fun LayoutBasedSwipeableSample() {
    val swipeableState = rememberSwipeableState(0)
    val anchors = remember { mutableStateMapOf<Float, Int>() }

    Layout(
        content = {
            // 可滑动的子组件
            Box(
                modifier = Modifier
                    .size(48.dp)
                    .background(Color.Blue)
                    .offset { IntOffset(swipeableState.offset.value.roundToInt(), 0) }
            )
        }
    ) { measurables, constraints ->
        val squarePlaceable = measurables.first().measure(constraints)
        // 容器宽度取约束最大值,可根据需求自定义
        val containerWidth = constraints.maxWidth.toFloat()
        val maxOffset = (containerWidth - squarePlaceable.width).coerceAtLeast(0f)

        // 更新锚点映射
        anchors.apply {
            clear()
            put(0f, 0)
            put(maxOffset, 1)
        }

        // 布局容器和子组件
        layout(constraints.maxWidth, squarePlaceable.height) {
            squarePlaceable.place(0, 0)
        }
    }
    .then(
        if (anchors.isNotEmpty()) {
            Modifier.swipeable(
                state = swipeableState,
                anchors = anchors,
                thresholds = { _, _ -> FractionalThreshold(0.3f) },
                orientation = Orientation.Horizontal
            )
        } else {
            Modifier
        }
    )
    .background(Color.LightGray)
}

关键说明:

  • Layout组件直接获取子组件的测量尺寸和容器约束,能精准计算可滑动的最大偏移量
  • 适合需要自定义容器尺寸规则的场景

注意事项

  • swipeable属于实验性API,使用时需添加@OptIn(ExperimentalMaterialApi::class)注解
  • 若后续AnchoredDraggable稳定后,可考虑迁移到该API以简化实现

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 18:46:14