Compose笔记(二十三)--多点触控

这一节主要了解一下Compose中多点触控,在Jetpack Compose 中,多点触控处理需要结合Modifier和手势API来实现,一般通过组合 pointerInput、TransformableState 和 TransformModifier 来创建支持缩放、旋转和平移的组件。

一、 API

  1. PointerInput

含义:处理低级触摸事件的主要API,支持多点触控。

用法:通过pointerInput修饰符拦截和处理触摸事件。

  1. TransformableState

含义:管理变换状态(缩放、旋转、平移)的状态容器。

用法:与transformable修饰符结合,监听手势并更新变换值。

  1. TransformModifier

含义:应用变换效果(缩放、旋转、平移)的修饰符。

用法:通过graphicsLayer或transformable应用变换。
二、关键类与接口

  1. PointerInputScope

提供处理触摸事件的作用域,包含:

detectDragGestures:处理单指拖拽。

detectTransformGestures:处理双指缩放 / 旋转。

detectTapGestures:处理点击事件。

  1. TransformScope

在detectTransformGestures中提供:

panChange:平移变化量。

zoomChange:缩放变化量。

rotationChange:旋转变化量。

  1. Transformation

包含三个变换参数:

scale:缩放因子。

rotation:旋转角度。

offset:平移偏移量。

栗子:

  1. 单指拖拽
Kotlin 复制代码
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.consumeAllChanges
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import com.example.composenavigationdemo.R

@Composable
fun TestImage() {
    var offset by remember { mutableStateOf(Offset.Zero) }

    Box(
        modifier = Modifier
            .size(200.dp)
            .background(Color.LightGray)
            .pointerInput(Unit) {
                detectDragGestures { change, dragAmount ->
                    // 阻止事件冒泡
                    change.consumeAllChanges()
                    // 更新偏移量
                    offset = offset + dragAmount
                }
            }
            .graphicsLayer {
                translationX = offset.x
                translationY = offset.y
            }
    ) {
        Image(
            painter = painterResource(R.drawable.android),
            contentDescription = null,
            modifier = Modifier.fillMaxSize()
        )
    }
}
  1. 双指缩放与旋转
Kotlin 复制代码
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.detectTransformGestures
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.res.painterResource
import com.example.composenavigationdemo.R

@Composable
fun TestImage() {
    var scale by remember { mutableStateOf(1f) }
    var rotation by remember { mutableStateOf(0f) }
    var offset by remember { mutableStateOf(Offset.Zero) }

    Box(
        modifier = Modifier
            .fillMaxSize()
            .background(Color.LightGray)
            .pointerInput(Unit) {
                detectTransformGestures { centroid, pan, zoom, rotationChange ->
                    // 更新变换参数
                    scale = (scale * zoom).coerceIn(0.5f, 5f)
                    rotation += rotationChange
                    offset = centroid
                }
            }
    ) {
        Image(
            painter = painterResource(R.drawable.android),
            contentDescription = null,
            modifier = Modifier
                .align(Alignment.Center)
                .graphicsLayer {
                    scaleX = scale
                    scaleY = scale
                    rotationZ = rotation
                    translationX = offset.x - size.width / 2
                    translationY = offset.y - size.height / 2
                }
        )
    }
}

3 组合多种手势

Kotlin 复制代码
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.gestures.detectTransformGestures
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.res.painterResource
import com.example.composenavigationdemo.R
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch

@Composable
fun TestImage() {
    var scale by remember { mutableStateOf(1f) }
    var rotation by remember { mutableStateOf(0f) }
    var offset by remember { mutableStateOf(Offset.Zero) }
    var isDragging by remember { mutableStateOf(false) }

    Box(
        modifier = Modifier
            .fillMaxSize()
            .background(Color.LightGray)
            .pointerInput(Unit) {
                coroutineScope {
                    launch {
                      
                        detectDragGestures(
                            onDragStart = { isDragging = true },
                            onDragEnd = { isDragging = false }
                        ) { change, dragAmount ->
                            offset += dragAmount
                        }
                    }

                    launch {
                  
                        detectTransformGestures(
                            panZoomLock = true
                        ) { _, pan, zoom, rotationChange ->
                            scale *= zoom
                            rotation += rotationChange
                            offset += pan
                        }
                    }
                }
            }
            .graphicsLayer {
                scaleX = scale
                scaleY = scale
                rotationZ = rotation
                translationX = offset.x
                translationY = offset.y
            }
    ) {
        Image(
            painter = painterResource(R.drawable.android),
            contentDescription = null,
            modifier = Modifier.align(Alignment.Center)
        )
    }
}

注意:

1 事件消费:通过change.consumeAllChanges()阻止事件冒泡。

2 坐标系转换:注意centroid(双指中心点)和offset的坐标系差异。

3 状态管理:使用remember保存变换状态,确保配置变更后状态恢复。

相关推荐
chouchuang9 小时前
day-030-综合练习-笔记管理器
开发语言·笔记·python
岑梓铭14 小时前
《考研408数据结构》第六章(6.3 图的遍历)复习笔记
数据结构·笔记·考研··拓扑排序·408
he_wen_jian14 小时前
【无标题】
笔记
灵性(๑>ڡ<)☆15 小时前
Java学习笔记--面向对象高级(多态)
笔记·学习
智者知已应修善业15 小时前
【51单片机实现初始化数码管不显示按启动从0秒计时到60按暂停一次显示当前秒按2次恢复原始状态】2024-6-11
c语言·c++·经验分享·笔记·嵌入式硬件·算法·51单片机
AA陈超15 小时前
003 XiYou 西游 — P0 阶段实施计划
c++·笔记·学习·ue5
沪上企服通16 小时前
上海地区代账服务供给侧的五种架构形态:从 pipeline SLA 到领域深度的选型笔记
笔记·架构
库玛西18 小时前
深入剖析 Linux 线程机制与分页式存储管理
linux·服务器·c++·笔记
奋发向前wcx18 小时前
y1,y2总复习笔记2 2026.7.15
java·笔记·算法
苦瓜汤补钙18 小时前
Oracle JDK8 环境配置-Win11
开发语言·数据库·笔记·oracle