简单介绍下Compose的Draggable Modifier

1,199 阅读2分钟

这是我参与更文挑战的第3天,活动详情查看: 更文挑战

目前有一个正在进行的 Jetpack Compose中文手册 项目,旨在帮助开发者更好的理解和掌握Compose框架,目前仍还在开荒中,欢迎大家进行关注与加入! 这篇文章由本人撰写,目前已经发布到该手册中,欢迎进行查阅。

1. Draggable能做什么

draggable 修饰符允许开发者监听UI组件的拖动手势偏移量,通过偏移量从而可以定制UI动画效果。

值得注意的是, draggable 修饰符只能监听垂直方向偏移或水平方向偏移。

2. Draggable参数列表

使用 draggable 修饰符至少需要传入两个参数 draggableStateorientation

draggableState:通过 draggableState 可以获取到拖动手势的偏移量,并允许开发者动态控制偏移量

orientation:监听的拖动手势方向,只能是水平方向(Orientation.Horizontal)或垂直方向(Orientation.Vertical)

fun Modifier.draggable(
    state: DraggableState,
    orientation: Orientation,
    enabled: Boolean = true,
    interactionSource: MutableInteractionSource? = null,
    startDragImmediately: Boolean = false,
    onDragStarted: suspend CoroutineScope.(startedPosition: Offset) -> Unit = {},
    onDragStopped: suspend CoroutineScope.(velocity: Float) -> Unit = {},
    reverseDirection: Boolean = false
)

3. Draggable使用示例

在本节中,我们将使用 Draggable 修饰符完成一个简单的滑块拖动动画。

首先我们定义了滑块偏移量以及滑块的边长。

通过 rememberDraggableState 方法获取 DraggableState 实例,通过回调lambda监听当前的偏移量并进行累加,并且限制了滑块的偏移区间。

var offsetX by remember {mutableStateOf(0f)}
val boxSideLengthDp = 50.dp
val boxSildeLengthPx = with(LocalDensity.current) {
    boxSideLengthDp.toPx()
}
val draggableState = rememberDraggableState {
    offsetX = (offsetX + it).coerceIn(0f, 3 * boxSildeLengthPx)
}

接下来我们将为 draggable 修饰符提供给draggableState与orientation了。

注意:由于Modifer链式执行,此时offset必需在draggable与background前面。

⚠️错误示例1(draggable在offset前面): 第二次拖动时UI控件拖动只能拖动初始位置才生效,不会跟随UI控件而移动监听,原因是每次拖动时draggable都监听的都是初始位置,不是偏移后位置。

⚠️错误示例2(background在offset前面): UI控件绘制的黑块不会跟手,原因在于每次绘制时background都在初始位置绘制,不是偏移后位置。

Box(
    Modifier
        .width(boxSideLengthDp * 4)
        .height(boxSideLengthDp)
        .background(Color.LightGray)
) {
    Box(
        Modifier
            .size(boxSideLengthDp)
            .offset {
                IntOffset(offsetX.roundToInt(), 0)
            }
            .draggable(
                orientation = Orientation.Horizontal,
                state = draggableState
            )
            .background(Color.DarkGray)
    )
}

效果展示

demo1.gif