一、前言
Compose
中手势会比在xml的方式要使用更广泛些,所以手势是有必要记录一下的。
二、clickable
在Compose
中对手势封装了一些单击、双击、长按事件。不过点击事件用的更多一些,这里进行简单的演示
@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 }
)
}
三、detectTapGestures
如果想要对基本的手势进行监测,则可以使用PointerInputScope.detectTapGestures
或 PointerInputScope.detectDragGestures
PointerInputScope.detectTapGestures
的大致用法如下:
Modifier.pointerInput(Unit) {
detectTapGestures(
onPress = { /* Called when the gesture starts */ },
onDoubleTap = { /* Called on Double Tap */ },
onLongPress = { /* Called on Long Press */ },
onTap = { /* Called on Tap */ }
)
}
具体示例如下
@Composable
private fun scrollBoxes() {
Column(
modifier = Modifier
.background(Color.LightGray)
.size(100.dp)
.verticalScroll(rememberScrollState())
.pointerInput(Unit){
detectTapGestures(
onPress = { /* Called when the gesture starts */ },
onDoubleTap = { /* Called on Double Tap */ },
onLongPress = { /* Called on Long Press */ },
onTap = { /* Called on Tap */ }
)
}
) {
repeat(10) {
Text("Item $it", modifier = Modifier.padding(2.dp))
}
}
}
PointerInputScope.detectDragGestures
手势拖动教程可以参考以下链接:
四、Dragging
dragging可以检测手势单一方向拖动,但是并不会移动元素。如果想移动的话可以通过offset
来进行移动,如下所示:
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!"
)
如果想要控制整个手势拖动,可以pointerInput
来进行监测,如下所示:
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.consumeAllChanges()
offsetX += dragAmount.x
offsetY += dragAmount.y
}
}
)
}
五、Swiping
有时候会有滑动切换或者滑动关闭等类似需求,可以使用swipeable
修饰符进行实现,该 swipeable
修改器允许您将它发布的时候,通常对两个或两个以上的锚点动画中的方向定义的元素。对此的常见用法是实现“滑动到关闭”模式。
需要注意的是,这个修饰符不会移动元素,它只检测手势。您需要保持状态并在屏幕上表示它,例如,通过offset
修改器移动元素 。
swipeable
修改器中需要可滑动状态,可以使用 来创建和记住 rememberSwipeableState()
。这种状态下还提供了(见以编程动画的一组有用的方法来锚 snapTo
, animateTo
, performFling
,和 performDrag
),以及属性来观察拖动进展。
滑动手势可以配置为具有不同的阈值类型,例如 FixedThreshold(Dp)
和 FractionalThreshold(Float)
,并且对于每个锚点从到组合,它们可以不同。
为了获得更大的灵活性,您可以配置resistance
何时滑动越过边界,并且velocityThreshold
即使thresholds
尚未到达位置,也可以将滑动动画设置为下一个状态。
@ExperimentalMaterialApi
@Composable
private fun swipeableSample() {
val width = 96.dp
val squareSize = 48.dp
val swipeableState = rememberSwipeableState(0)
val sizePx = with(LocalDensity.current) { squareSize.toPx() }
Log.e("YM","sizePx--$sizePx")
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)
) {
Box(
Modifier
.offset { IntOffset(swipeableState.offset.value.roundToInt(), 0) }
.size(squareSize)
.background(Color.DarkGray)
)
}
}
第二个swipeable
,用来加深对anchors
的理解
@ExperimentalMaterialApi
@Composable
private fun swipeableSample2() {
// Draw a slider-like composable consisting of a red square moving along a
// black background, with three states: "A" (min), "B" (middle), and "C" (max).
val width = 350.dp
val squareSize = 50.dp
val swipeableState = rememberSwipeableState("A")
val sizePx = with(LocalDensity.current) { (width - squareSize).toPx() }
val anchors = mapOf(0f to "A", sizePx / 2 to "B", sizePx to "C")
Box(
modifier = Modifier
.width(width)
.swipeable(
state = swipeableState,
anchors = anchors,
thresholds = { _, _ -> FractionalThreshold(0.5f) },
orientation = Orientation.Horizontal
)
.background(Color.Black)
) {
Box(
Modifier
.offset { IntOffset(swipeableState.offset.value.roundToInt(), 0) }
.size(squareSize)
.background(Color.Red),
contentAlignment = Alignment.Center
) {
Text(swipeableState.currentValue, color = Color.White, fontSize = 24.sp)
}
}
}
六、多点触控:平移、缩放、旋转
要检测用于平移、缩放和旋转的多点触控手势,您可以使用transformable
修饰符。此修改器本身不会变换元素,它只检测手势。
@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)
.fillMaxSize()
)
}
如果您需要将缩放、平移和旋转与其他手势结合使用,则可以使用 PointerInputScope.detectTransformGestures
检测器。
七、事件分发
https://compose.net.cn/design/gesture/custom_gesture/
八、基础事件
上述的事件都是从基础事件封装的,这里简单记录一下基础事件的使用链接,后续完善,可以实现按下时候一个效果,抬起时候一个效果,这种效果上述的几种手势无法完成该操作
- Compose实现状态选择器(原生drawable select标签效果) InteractionSource:https://blog.csdn.net/qq_33505109/article/details/124478228
- InteractionSource:https://developer.android.google.cn/reference/kotlin/androidx/compose/foundation/interaction/InteractionSource#public-properties_1
- 处理用户互动:https://developer.android.google.cn/jetpack/compose/handling-interaction#icon-button-example
八、参考链接
-
Modifier
https://developer.android.google.cn/reference/kotlin/androidx/compose/ui/Modifie
-
监测手势拖动detectDragGestures
-
androidx.compose.material
https://developer.android.google.cn/reference/kotlin/androidx/compose/material/package-summary
-
swipeable中的可选修饰符
-
transformable的修饰符说明