? ? ? ? ?這一節主要了解一下Compose中多點觸控,在Jetpack Compose 中,多點觸控處理需要結合Modifier和手勢API來實現,一般通過組合 pointerInput、TransformableState 和 TransformModifier 來創建支持縮放、旋轉和平移的組件。
一、 API
1. PointerInput
含義:處理低級觸摸事件的主要API,支持多點觸控。
用法:通過pointerInput修飾符攔截和處理觸摸事件。
2. TransformableState
含義:管理變換狀態(縮放、旋轉、平移)的狀態容器。
用法:與transformable修飾符結合,監聽手勢并更新變換值。
3. TransformModifier
含義:應用變換效果(縮放、旋轉、平移)的修飾符。
用法:通過graphicsLayer或transformable應用變換。
二、關鍵類與接口
1. PointerInputScope
提供處理觸摸事件的作用域,包含:
detectDragGestures:處理單指拖拽。
detectTransformGestures:處理雙指縮放 / 旋轉。
detectTapGestures:處理點擊事件。
2. TransformScope
在detectTransformGestures中提供:
panChange:平移變化量。
zoomChange:縮放變化量。
rotationChange:旋轉變化量。
3. Transformation
包含三個變換參數:
scale:縮放因子。
rotation:旋轉角度。
offset:平移偏移量。
栗子:
1. 單指拖拽
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.xtranslationY = offset.y}) {Image(painter = painterResource(R.drawable.android),contentDescription = null,modifier = Modifier.fillMaxSize())}
}
2. 雙指縮放與旋轉
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 += rotationChangeoffset = centroid}}) {Image(painter = painterResource(R.drawable.android),contentDescription = null,modifier = Modifier.align(Alignment.Center).graphicsLayer {scaleX = scalescaleY = scalerotationZ = rotationtranslationX = offset.x - size.width / 2translationY = offset.y - size.height / 2})}
}
3?組合多種手勢
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 *= zoomrotation += rotationChangeoffset += pan}}}}.graphicsLayer {scaleX = scalescaleY = scalerotationZ = rotationtranslationX = offset.xtranslationY = offset.y}) {Image(painter = painterResource(R.drawable.android),contentDescription = null,modifier = Modifier.align(Alignment.Center))}
}
注意:
1 事件消費:通過change.consumeAllChanges()阻止事件冒泡。
2 坐標系轉換:注意centroid(雙指中心點)和offset的坐標系差異。
3 狀態管理:使用remember保存變換狀態,確保配置變更后狀態恢復。