JetpackCompose从入门到实战学习笔记6——手势的简单使用

JetpackCompose从入门到实战学习笔记6——手势的简单使用

手势

Compose 提供了多种 API,可帮助您检测用户互动生成的手势。API 涵盖各种用例:

  • 其中一些级别较高,旨在覆盖最常用的手势。例如,clickable 修饰符可用于轻松检测点击,此外它还提供无障碍功能,并在点按时显示视觉指示(例如涟漪)。
  • 还有一些不太常用的手势检测器,它们在较低级别提供更大的灵活性,例如 PointerInputScope.detectTapGesturesPointerInputScope.detectDragGestures,但不提供额外功能。

1.点击

clickable 修饰符允许应用检测对已应用该修饰符的元素的点击

@Composable
fun ClickableSample() {
    val count = remember { mutableStateOf(0) }
    // content that you want to make clickable
    Text(
        text = count.value.toString(),
        modifier = Modifier.clickable { count.value += 1 }
    )
}

2.效果预览:

在这里插入图片描述

3.滚动:

  • 滚动修饰符

  • verticalScrollhorizontalScroll 修饰符提供一种最简单的方法,可让用户在元素内容边界大于最大尺寸约束时滚动元素。利用 verticalScrollhorizontalScroll 修饰符,您无需转换或偏移内容。

    @Composable
    fun ScrollBoxes() {
        Column(
            modifier = Modifier
                .background(Color.LightGray)
                .size(200.dp)
                .verticalScroll(rememberScrollState())
        ) {
            repeat(20) {
                Text("滚动的Item $it", modifier = Modifier.padding(2.dp))
            }
        }
    }

4.效果预览:

在这里插入图片描述

5.可滚动的修饰符

scrollable 修饰符与滚动修饰符不同,区别在于 scrollable 可检测滚动手势,但不会偏移其内容。必须有 ScrollableState,此修饰符才能正常工作。构造 ScrollableState 时,您必须提供一个 consumeScrollDelta 函数,该函数将在每个滚动步骤调用(通过手势输入、流畅滚动或快速滑动),并且增量以像素为单位。该函数必须返回所消耗的滚动距离,以确保在存在具有 scrollable 修饰符的嵌套元素时,可以正确传播相应事件。

    @Composable
    private fun ScrollBoxesSmooth() {
        var offsets: Float by remember { mutableStateOf(0f) }
        Box(
            Modifier
                .size(200.dp)
                .scrollable(
                    orientation = Orientation.Vertical,
                // Scrollable state: describes how to consume
                // scrolling delta and update offset
                    state = rememberScrollableState { delta ->
                        offsets += delta
                        delta
                    }
                )
                .background(Color.LightGray),
            contentAlignment = Alignment.Center
        ) {
            Text(offsets.toString())
        }
    }

6.效果预览:

在这里插入图片描述

7.嵌套滚动

  • Compose 支持嵌套滚动,可让多个元素对一个滚动手势做出回应。典型的嵌套滚动示例是在一个列表中嵌套另一个列表,而收起工具栏则是一种较为复杂的嵌套滚动情况。
  • 自动嵌套滚动
  • 简单的嵌套滚动无需您执行任何操作。启动滚动操作的手势会自动从子级传播到父级,这样一来,当子级无法进一步滚动时,手势就会由其父元素处理。
  • 部分 Compose 组件和修饰符原生支持自动嵌套滚动,包括:verticalScrollhorizontalScrollscrollableLazy API 和 TextField。这意味着,当用户滚动嵌套组件的内部子级时,之前的修饰符会将滚动增量传播到支持嵌套滚动的父级。
  • 以下示例显示的元素应用了 verticalScroll 修饰符,而其所在的容器同样应用了 verticalScroll 修饰符。
@Composable
fun ScrollableSample() {
    // actual composable state
    var offset by remember { mutableStateOf(0f) }
    Box(
        Modifier
            .size(200.dp)
            .scrollable(
                orientation = Orientation.Vertical,
                // Scrollable state: describes how to consume
                // scrolling delta and update offset
                state = rememberScrollableState { delta ->
                    offset += delta
                    delta
                }
            )
            .background(Color.LightGray),
        contentAlignment = Alignment.Center
    ) {
        Text(offset.toString())
    }

    val gradient = Brush.verticalGradient(0f to Color.Gray, 1000f to Color.White)
    Box(
        modifier = Modifier
            .background(Color.LightGray)
            .verticalScroll(rememberScrollState())
            .padding(32.dp)
    ) {
        Column {
            repeat(6) {
                Box(
                    modifier = Modifier
                        .height(128.dp)
                        .verticalScroll(rememberScrollState())
                ) {
                    Text(
                        "Scroll here",
                        modifier = Modifier
                            .border(12.dp, Color.DarkGray)
                            .background(brush = gradient)
                            .padding(24.dp)
                            .height(200.dp)
                    )
                }
            }
        }
    }
}

8.效果预览:

在这里插入图片描述

9.拖动:

draggable 修饰符是向单一方向拖动手势的高级入口点,并且会报告拖动距离(以像素为单位)。

请务必注意,此修饰符与 scrollable 类似,仅检测手势。您需要保存状态并在屏幕上表示

9.1.单一拖动:

   @Composable
    fun singleDraggableSample() {
        var offsetX by remember { mutableStateOf(0f) }
        Box(
            modifier = Modifier
                .fillMaxWidth()
            	.height(200.dp)
                .offset { IntOffset(offsetX.roundToInt(), 0) }
                .draggable(
                    state = rememberDraggableState {
                        offsetX += it
                    },
                    orientation = Orientation.Horizontal
                )
                .background(Color.Red),
            contentAlignment = Alignment.Center
        ) {
            Text(
                text = "单一拖动",
                style = MaterialTheme.typography.bodySmall.copy(color = Color.White)
            )
        }
    }

9.2.单一拖动效果预览:

在这里插入图片描述

9.3.任意位置的拖动:

    @Composable
    fun DraggableSample() {
        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(200.dp)
                    .pointerInput(Unit) {
                        detectDragGestures { change, dragAmount ->
                            change.consumeAllChanges()
                            offsetX += dragAmount.x
                            offsetY += dragAmount.y
                        }
                    }
            ) {
                Text(
                    text = "任意位置拖动",
                    style = MaterialTheme.typography.bodySmall.copy(color = Color.White)
                )
            }
        }
    }

9.4 任意位置效果预览:

在这里插入图片描述

10.左右滑动:

val width = 200.dp
val squareSize = 100.dp
val swipeAbleState = rememberSwipeableState(0)
val sizePx = with(LocalDensity.current) { squareSize.toPx() }
val anchors = mapOf(0f to 0, sizePx to 1) // Maps anchor points (in px) to states
Box(
    modifier = Modifier
        .width(width)
        .swipeable(
            state = swipeAbleState,
            anchors = anchors,
            thresholds = { _, _ -> FractionalThreshold(0.3f) },
            orientation = Orientation.Horizontal
        )
        .background(Color.LightGray),
    contentAlignment = Alignment.CenterStart
) {
    Box(
        Modifier
            .offset { IntOffset(swipeAbleState.offset.value.roundToInt(), 0) }
            .size(squareSize)
            .background(Color.Cyan)
    )
    Text(text = "左右滑动", textAlign = TextAlign.Center, style = MaterialTheme.typography.bodySmall.copy(color = Color.White))
}

11.效果预览:

在这里插入图片描述

12.多点触控:平移、缩放、旋转

@Composable
fun TransformableSample() {
    // set up all transformation states
    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
            // apply other transformations like rotation and zoom
            // on the pizza slice emoji
            .graphicsLayer(
                scaleX = scale,
                scaleY = scale,
                rotationZ = rotation,
                translationX = offset.x,
                translationY = offset.y
            )
            // add transformable to listen to multitouch transformation events
            // after offset
            .transformable(state = state)
            .background(Color.Blue)
            .size(200.dp)
    )
}

13.完整代码:

   @OptIn(ExperimentalMaterialApi::class)
    @Composable
    private fun AllGestures() {
        Column(modifier = Modifier.fillMaxSize()) {
            // content that you want to make clickable
            Row {
                val count = remember { mutableStateOf(0) }
                Box(
                    modifier = Modifier
                        .size(200.dp)
                        .background(Color.DarkGray)
                        .clickable { count.value += 1 },
                    contentAlignment = Alignment.Center
                ) {
                    Text(
                        text = "点击改变" + count.value.toString(),
                        style = MaterialTheme.typography.bodySmall.copy(color = Color.White)
                    )
                }
                Spacer(modifier = Modifier.width(30.dp))
                // Smoothly scroll 100px on first composition
                val states = rememberScrollState()
                LaunchedEffect(Unit) { states.animateScrollTo(200) }
                Column(
                    modifier = Modifier
                        .background(Color.Magenta)
                        .size(200.dp)
                        .padding(horizontal = 8.dp)
                        .verticalScroll(states)
                ) {
                    repeat(20) {
                        Text(
                            "滚动的Item $it",
                            modifier = Modifier.padding(2.dp),
                            style = MaterialTheme.typography.bodySmall.copy(color = Color.White)
                        )
                    }
                }
                Spacer(modifier = Modifier.width(20.dp))
                // actual composable state
                var offsets: Float by remember { mutableStateOf(0f) }
                Box(
                    Modifier
                        .size(200.dp)
                        .scrollable(
                            orientation = Orientation.Vertical,
                            // Scrollable state: describes how to consume
                            // scrolling delta and update offset
                            state = rememberScrollableState { delta ->
                                offsets += delta
                                delta
                            }
                        )
                        .background(Color.LightGray),
                    contentAlignment = Alignment.Center
                ) {
                    Text(offsets.toString())
                }
            }
            //嵌套滚动
            Row() {
                Spacer(Modifier.width(20.dp))
                val gradient = Brush.verticalGradient(0f to Color.Gray, 1000f to Color.White)
                Box(
                    modifier = Modifier
                        .background(Color.LightGray)
                        .verticalScroll(rememberScrollState())
                        .padding(32.dp)
                ) {
                    Column {
                        repeat(6) {
                            Box(
                                modifier = Modifier
                                    .height(128.dp)
                                    .verticalScroll(rememberScrollState())
                            ) {
                                Text(
                                    "Scroll here",
                                    modifier = Modifier
                                        .border(12.dp, Color.DarkGray)
                                        .background(brush = gradient)
                                        .padding(24.dp)
                                        .height(200.dp)
                                )
                            }
                        }
                    }
                }
                Spacer(modifier = Modifier.width(20.dp))
                //左右滑动
                val width = 200.dp
                val squareSize = 100.dp
                val swipeAbleState = rememberSwipeableState(0)
                val sizePx = with(LocalDensity.current) { squareSize.toPx() }
                val anchors = mapOf(0f to 0, sizePx to 1) // Maps anchor points (in px) to states
                Box(
                    modifier = Modifier
                        .width(width)
                        .swipeable(
                            state = swipeAbleState,
                            anchors = anchors,
                            thresholds = { _, _ -> FractionalThreshold(0.3f) },
                            orientation = Orientation.Horizontal
                        )
                        .background(Color.LightGray),
                    contentAlignment = Alignment.CenterStart
                ) {
                    Box(
                        Modifier
                            .offset { IntOffset(swipeAbleState.offset.value.roundToInt(), 0) }
                            .size(squareSize)
                            .background(Color.Cyan)
                    )
                    Text(
                        text = "左右滑动",
                        textAlign = TextAlign.Center,
                        style = MaterialTheme.typography.bodySmall.copy(color = Color.White)
                    )
                }
                Spacer(modifier = Modifier.width(20.dp))
                var offsetX by remember { mutableStateOf(0f) }
                var offsetY by remember { mutableStateOf(0f) }
                Box(
                    modifier = Modifier
                        .size(100.dp)
                        .offset { IntOffset(offsetX.roundToInt(), 0) }
                        .draggable(
                            state = rememberDraggableState {
                                offsetX += it
                            },
                            orientation = Orientation.Horizontal
                        )
                        .background(Color.Red),
                    contentAlignment = Alignment.Center
                ) {
                    Text(
                        text = "单一拖动",
                        style = MaterialTheme.typography.bodySmall.copy(color = Color.White)
                    )
                }
                Spacer(modifier = Modifier.width(20.dp))
                //拖动任意位置
                var offX by remember { mutableStateOf(0f) }
                var offY by remember { mutableStateOf(0f) }
                Box(
                    Modifier
                        .offset { IntOffset(offX.roundToInt(), offY.roundToInt()) }
                        .background(Color.Blue)
                        .size(200.dp)
                        .pointerInput(Unit) {
                            detectDragGestures { change, dragAmount ->
                                change.consumeAllChanges()
                                offX += dragAmount.x
                                offY += dragAmount.y
                            }
                        },
                    contentAlignment = Alignment.Center
                ) {
                    Text(
                        text = "任意位置拖动",
                        style = MaterialTheme.typography.bodySmall.copy(color = Color.White)
                    )
                }

                Spacer(modifier = Modifier.width(20.dp))
                // set up all transformation states
                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
                        // apply other transformations like rotation and zoom
                        // on the pizza slice emoji
                        .graphicsLayer(
                            scaleX = scale,
                            scaleY = scale,
                            rotationZ = rotation,
                            translationX = offset.x,
                            translationY = offset.y
                        )
                        // add transformable to listen to multitouch transformation events
                        // after offset
                        .transformable(state = state)
                        .background(Color.Blue)
                        .width(200.dp)
                )
            }
        }
    }

14.完整效果预览:

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值