> 文章列表 > Compose (11/N) - 手势

Compose (11/N) - 手势

Compose (11/N) - 手势

一、点击

1.1 可点击 Modifier.clickable( )

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

@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 还可以更改滚动位置或获取当前状态。

@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( ) 函数,该函数在每个滚动步骤都会调用,以像素为单位,返回所消耗的距离。

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

2.3 嵌套滚动

2.3.1 自动嵌套滚动

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

//父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 修饰符使用手势检测。

//父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.xoffsetY += dragAmount.y}})}
}

四、滑动 Modifier.swipeable( )

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

@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( )

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

@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 *= zoomChangerotation += rotationChangeoffset += offsetChange}Box(Modifier.graphicsLayer(scaleX = scale,    //等比缩放scaleY = scale,    //等比缩放rotationZ = rotation,translationX = offset.x,translationY = offset.y).transformable(state = state).background(Color.Blue).fillMaxSize())
}