Compose (11/N) - 手势

一、点击

1.1 可点击 Modifier.clickable( )

允许应用检测对该元素的点击。

Compose (11/N) - 手势_第1张图片

@Composable
fun ClickableSample() {
    val count = remember { mutableStateOf(0) }
    Text(
        text = count.value.toString(),
        modifier = Modifier.clickable { count.value += 1 }
    )
}

1.2 手势检测 Modifier.pointerInput( )

当需要更大灵活性时,提供点按手势检测器。

detectTapGestures(
    onDoubleTap: ((Offset) -> Unit)? = null,        //双击
    onLongPress: ((Offset) -> Unit)? = null,        //长按
    onPress: suspend PressGestureScope.(Offset) -> Unit = NoPressGesture, //短按(其它三个都会触发有一次)
    onTap: ((Offset) -> Unit)? = null        //单击
)

检测点击手势

detectDragGestures(
    onDragStart: (Offset) -> Unit = { },
    onDragEnd: () -> Unit = { },
    onDragCancel: () -> Unit = { },
    onDrag: (change: PointerInputChange, dragAmount: Offset) -> Unit        //dragAmount拖动距离
)

检测拖动手势:dragAmount.x 和 dragAmount.y 拿到各方向上的拖动距离。

Modifier.pointerInput(Unit) {
    detectTapGestures(
        ...
    )
}

二、滚动

2.1 滚动修饰符 Modifier.verticalScroll( )、Modifier.horizontalScroll( )

Modifier.verticalScroll 和 Modifier.horizontalScroll 可以让内容边界大于最大尺寸约束时滚动里面的元素。借助 ScrollState 还可以更改滚动位置或获取当前状态。

Compose (11/N) - 手势_第2张图片

@Composable
fun ScrollBoxes() {
    val scrollState = rememberScrollState()
    LaunchedEffect(Unit) { scrollState.animateScrollTo(100) }
    Column(
        modifier = Modifier
            .background(Color.LightGray)
            .size(100.dp)
//            .verticalScroll(rememberScrollState())  //使用默认参数
            .verticalScroll(scrollState)    //一显示就会自动滚动100px
    ) {
        repeat(10) {
            Text("Item $it", modifier = Modifier.padding(2.dp))
        }
    }
}

2.2 可滚动修饰符 Modifier.scrollable( )

只检测手势不偏移内容。构造时需要提供一个 consumeScrollDelta( ) 函数,该函数在每个滚动步骤都会调用,以像素为单位,返回所消耗的距离。

Compose (11/N) - 手势_第3张图片

@Composable
fun ScrollableSample() {
    var offset by remember { mutableStateOf(0f) }
    Box(
        Modifier
            .size(150.dp)
            .scrollable(
                orientation = Orientation.Vertical,
                state = rememberScrollableState { delta ->
                    //拿到每次滑动的偏移量delta
                    offset += delta
                    delta
                }
            )
            .background(Color.LightGray),
        contentAlignment = Alignment.Center
    ) {
        Text(offset.toString())
    }
}

2.3 嵌套滚动

2.3.1 自动嵌套滚动

简单的嵌套滚动无需额外操作,当子元素无法进一步滚动时手势会由父元素处理,手势会自动从子元素传播到父元素。

Compose (11/N) - 手势_第4张图片

//父Box嵌套10个子Box,子Box滚动到边界会滚动父Box
@Composable
fun ScrollableSample() {
    //设置渐变色方便观察子Box滚动(蓝→黄1000级)
    val gradient = Brush.verticalGradient(0f to Color.Blue, 1000f to Color.Yellow)
    Box(
        modifier = Modifier
            .background(Color.LightGray)
            .verticalScroll(rememberScrollState())
            .padding(32.dp)
    ) {
        Column {
            repeat(10) {
                Box(
                    modifier = Modifier
                        .height(128.dp)
                        .verticalScroll(rememberScrollState())
                ) {
                    Text(
                        text = "Scroll here",
                        color = Color.Red,
                        modifier = Modifier
                            .border(12.dp, Color.DarkGray)
                            .background(brush = gradient)
                            .padding(24.dp)
                            .height(150.dp)
                    )
                }
            }
        }
    }
}

2.3.2 nestedScroll 修饰符

2.3.3 嵌套滚动互操作性(v1.2.0)

三、拖动

只检测手势不偏移内容(需要保存状态并在屏幕上表示,例如通过 offset 修饰符移动元素),以像素为单位。

3.1 线性拖动(一维)Modifier.draggable( )

//文字横向拖动
var offsetX by remember { mutableStateOf(0f) }
Text(
    modifier = Modifier
        .offset { IntOffset(offsetX.roundToInt(), 0) }
        .draggable(
            orientation = Orientation.Horizontal,
            state = rememberDraggableState { delta ->
                offsetX += delta
            }
        ),
    text = "Drag me!"
)

3.2 平面拖动(二维)Modifier.pointerInput( )

改为 pointerInput 修饰符使用手势检测。

Compose (11/N) - 手势_第5张图片

//父Box中拖动蓝色子Box
@Composable
fun ScrollableSample() {
    Box(modifier = Modifier.fillMaxSize()) {
        var offsetX by remember { mutableStateOf(0f) }
        var offsetY by remember { mutableStateOf(0f) }
        Box(
            Modifier
                .offset { IntOffset(offsetX.roundToInt(), offsetY.roundToInt()) }
                .background(Color.Blue)
                .size(50.dp)
                .pointerInput(Unit) {
                    detectDragGestures { change, dragAmount ->
                        change.consume()
                        offsetX += dragAmount.x
                        offsetY += dragAmount.y
                    }
                }
        )
    }
}

四、滑动 Modifier.swipeable( )

只检测手势不偏移内容(需要保存状态并在屏幕上表示,例如通过 offset 修饰符移动元素)。具有惯性,释放后会朝着锚点呈现动画效果,常见用途是滑动关闭。

Compose (11/N) - 手势_第6张图片

@OptIn(ExperimentalMaterialApi::class)
@Composable
fun SwipeableSample() {
    val squareSize = 48.dp    //子Box的大小
    val swipeableState = rememberSwipeableState(0)
    val sizePx = with(LocalDensity.current) { squareSize.toPx() }   //DP转PX
    //设置锚点(key是像素,value是索引)
    val anchors = mapOf(0f to 0, sizePx to 1)
    Box(
        modifier = Modifier
            .width(96.dp)
            .swipeable(
                state = swipeableState,
                anchors = anchors,
                //阈值(超过就会自己滑到底,达不到就会滑回来)
                thresholds = { _, _ -> FractionalThreshold(0.3f) },
                orientation = Orientation.Horizontal
            )
            .background(Color.LightGray)
    ) {
        Box(
            Modifier
                .offset { IntOffset(swipeableState.offset.value.roundToInt(), 0) }
                .size(squareSize)
                .background(Color.DarkGray)
        )
    }
}

五、多点触控 Modifier.transformable( )

只检测手势不转换元素。平移、缩放、旋转。

Compose (11/N) - 手势_第7张图片

@Composable
fun TransformableSample() {
    var scale by remember { mutableStateOf(1f) }    //缩放
    var rotation by remember { mutableStateOf(0f) }    //旋转
    var offset by remember { mutableStateOf(Offset.Zero) }    //平移
    val state = rememberTransformableState { zoomChange, offsetChange, rotationChange ->
        scale *= zoomChange
        rotation += rotationChange
        offset += offsetChange
    }
    Box(
        Modifier
            .graphicsLayer(
                scaleX = scale,    //等比缩放
                scaleY = scale,    //等比缩放
                rotationZ = rotation,
                translationX = offset.x,
                translationY = offset.y
            )
            .transformable(state = state)
            .background(Color.Blue)
            .fillMaxSize()
    )
}

你可能感兴趣的:(Compose,android)