Jetpack Compose之手势使用

在一个应用中用户的交互操作非常多,如:点击、滑动、拖动等,这些操作统统离不开手势。
在正式介绍Compose手势前,我们先来了解下Jetpack Compose手势整体框架,做到心中有图。

Jetpack Compose手势类型

一、点击

这个含义都懂就不解释,实现点击采用的修饰符clickable,如下:

@Composable
private fun GestureOfClick(){
    var colorState by remember { mutableStateOf(false) }
    Box(modifier = Modifier
        .size(60.dp)
        .background(color = if (colorState) Color.LightGray else Color.Gray)
        .clickable { colorState = !colorState },
        contentAlignment = Alignment.Center
    ){
        Text(text = "点击")
    }
}

运行效果:
Compose手势-点击.gif
二、滚动

滚动修饰符实现
使用的修饰符为:verticalScroll或horizontalScroll,您无需转换或偏移内容。

val scrollState = rememberScrollState()
        Box(modifier = Modifier
            .size(60.dp)
            .background(color = Color.LightGray)
            .verticalScroll(scrollState),
            contentAlignment = Alignment.Center
        ){
            Text( text = "滚动"  )
        }

可滚动修饰符实现
使用修饰符为:scrollable,检测到滚动,但不会滚动,需与ScrollableController配合实现滚动。构造 ScrollableController 时,您必须提供一个 consumeScrollDelta 函数,该函数将在每个滚动步骤调用(通过手势输入、流畅滚动或快速滑动),并且增量以像素为单位。

var offset by remember { mutableStateOf(0f) }
        Box(
            modifier = Modifier
                .size(120.dp, 60.dp)
                .scrollable(
                    state = rememberScrollableState { delta ->
                        offset += delta
                        delta
                    },
                    orientation = Orientation.Vertical
                )
                .background(Color.LightGray),
            contentAlignment = Alignment.Center
        ) {
            Text(text = offset.toString())
        }

支持嵌套滚动
Compose 支持嵌套滚动,可让多个元素对一个滚动手势做出回应。典型的嵌套滚动示例是在一个列表中嵌套另一个列表。

val gradient = Brush.verticalGradient(0f to Color.Gray, 1000f to Color.White)
        Box(
            modifier = Modifier.size(120.dp, 80.dp)
                .background(color = Color.LightGray)
                .verticalScroll(rememberScrollState())
        ) {
            Column {
                repeat(5){
                    //内部嵌套滚动
                    Box(
                        modifier = Modifier.fillMaxWidth()
                            .height(60.dp).background(color = Color.LightGray)
                            .verticalScroll(rememberScrollState())
                    ) {
                        Text("Scroll here",
                            modifier = Modifier.fillMaxWidth().border(12.dp, Color.DarkGray).background(brush = gradient)
                                .padding(top = 20.dp, start = 10.dp).height(80.dp)
                        )
                    }
                }
            }
        }
滚动手势gif动态图
三、拖动

实现拖动有两种方式:
单一方向拖动 - draggable
draggable向单一方向(水平或垂直)拖动手势的高级入口点,并且会报告拖动距离(以像素为单位)。

Box(
        modifier = Modifier
            .size(60.dp)
            .offset { IntOffset(offsetX.roundToInt(), 0) }
            .draggable(
                state = rememberDraggableState {
                    offsetX += it
                },
                orientation = Orientation.Horizontal
            )
            .background(Color.Red),
        contentAlignment = Alignment.Center
    ) {
        Text(text = "拖动")
    }

任意方向拖动 - pointerInput
pointerInput 修饰符可以检测到手势变化及偏移量。

Box(
        modifier = Modifier.size(80.dp, 60.dp)
            .offset { IntOffset(offX.roundToInt(), offY.roundToInt()) }
            .pointerInput(Unit) {
                detectDragGestures { change, dragAmount ->
                    change.consumeAllChanges()
                    offX += dragAmount.x
                    offY += dragAmount.y
                }
            }
            .background(Color.Yellow),
        contentAlignment = Alignment.Center
    ){
        Text(text = "任意位置拖动")
    }

两种方式效果如下:
拖动gif动态图
四、滑动

滑动使用的修饰符为:swipeable,您可以拖动元素,释放后,这些元素通常朝一个方向定义的两个或多个锚点继续滑动以呈现动画效果。其常见用途是实现“滑动关闭”模式。
这里以滑块为例:

val width = 150.dp
    val squareSize = 75.dp
    val sizePx = with(LocalDensity.current){squareSize.toPx()}
    val swipeState = rememberSwipeableState(0)
    val anchors = mapOf(0f to 0,sizePx to 1)
    Box(
        modifier = Modifier
            .size(width, 40.dp)
            .background(color = Color.LightGray)
            .swipeable(
                state = swipeState,
                anchors = anchors,
                thresholds = { _, _ -> FractionalThreshold(0.3f) },
                orientation = Orientation.Horizontal,
            )
    ) {
        Box(
            modifier = Modifier
                .size(squareSize)
                //注意这里要放在background前面,否则出现无法滑动问题
                .offset { IntOffset(swipeState.offset.value.roundToInt(), 0) }
                .background(color = Color.Green)
        )
    }

效果如下:
滑动效果
五、多点触控

手势的多点触控可以实现组件的缩放、平移、旋转,采用的修饰符为:transformable和graphicsLayer组合方式
以一个长方形为例:

var scale by remember{ mutableStateOf(1f)}
    var translate by remember{ mutableStateOf(Offset.Zero)}
    var rotation by remember{ mutableStateOf(0f)}

    val state = rememberTransformableState{zoomChange: Float, panChange: Offset, rotationChange: Float->
        scale *= zoomChange
        translate += panChange
        rotation += rotationChange
    }
    Box(
        modifier = Modifier
            .size(120.dp,80.dp)
            .graphicsLayer(
                scaleX = scale,   //x轴的缩放值
                scaleY = scale,   //y轴的缩放值
                translationX = translate.x,//x轴的平移值
                translationY = translate.y,//y轴的平移值
                rotationZ = rotation        //旋转值
            )
            .transformable(state)
            .background(Color.Blue)
    )

效果如下:
多点触控动态效果
总结

Jetpack Compose中的手势实现均与修饰符(Modifier)有关。


总结

欢迎留言,一起学习,共同进步!

github - 示例源码
gitee - 示例源码

你可能感兴趣的:(Jetpack Compose之手势使用)