Compose几个简单手势

1,121 阅读3分钟

概览

Compose提供了多个api用来实现各种手势,这些手势包括点击、按压、双击、长按、水平垂直滑动、拖动、双指平移缩放旋转、嵌套欢动效果

各种手势效果介绍

点击手势

代码

Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
        Box(modifier = Modifier
            .size(200.dp)
            .background(Color.Green)
            .clickable {
                App.toast("被点击")
            }, contentAlignment = Alignment.Center
        ) {
            Text(text = "点击事件")
        }
    }

效果

单点、按压、双击、长按

代码

@Composable
fun PointerView() {
    Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
        Box(
            modifier = Modifier
                .size(200.dp)
                .background(Color.Green)
                .pointerInput(Unit) {
                    detectTapGestures(
                        onTap = {
                            App.toast("单点事件触发")
                        },
                        onDoubleTap = {
                            App.toast("双击事件")
                        },
                        onPress = {
//                            App.toast("按压事件")
                        },
                        onLongPress = {
                            App.toast("长按事件")
                        }
                    )
                }, contentAlignment = Alignment.Center
        ) {
            Text(text = "单点、双击、按压、长按事件")
        }
    }
}

说明

双击、单击、长按都会触发按压的效果回调, pointerInput.detectTapGestures

效果

水平和垂直滑动

代码

val list = (0..255)
    Column(
        Modifier
            .fillMaxSize()
            .verticalScroll(rememberScrollState())
    ) {
        Box(
            Modifier
                .fillMaxWidth(10f)
                .height(100.dp)
                .background(Color.Green)
                .horizontalScroll(rememberScrollState()),
            contentAlignment = Alignment.Center
        ) {
            Text(
                text = "安安安安卓,欢迎关注掘金号、公众号、csdn,分享android相关知识,安安安安卓,欢迎关注掘金号、公众号、csdn,分享android相关知识,安安安安卓,欢迎关注掘金号、公众号、csdn,分享android相关知识",
                style = TextStyle(color = Color.White, fontSize = 20.sp, fontWeight = FontWeight.Bold)
                )
        }

        repeat(40) {
            Box(
                Modifier
                    .height(80.dp)
                    .fillMaxWidth()
                    .background(Color(list.random(), list.random(), list.random())),
                contentAlignment = Alignment.Center
            ) {
                Text(text = it.toString(), style = TextStyle(color = Color.White, fontSize = 20.sp))
            }
        }
    }

说明

任何控件,只需要调用一下两个修饰符就可以实现滑动效果

.verticalScroll(rememberScrollState())

.horizontalScroll(rememberScrollState())

效果

拖动手势

代码

var offsetX by remember {
        mutableStateOf(0f)
    }
    var offsetY by remember {
        mutableStateOf(0f)
    }
    Box(Modifier.fillMaxSize()) {
        Box(
            Modifier
                .offset { IntOffset(offsetX.toInt(), offsetY.toInt()) }
                .size(200.dp)
                .background(Color.Green, shape = CircleShape)
                .pointerInput(Unit) {
                    detectDragGestures(onDrag = { pointerInputChange: PointerInputChange, offset: Offset ->
                        pointerInputChange.consumeAllChanges()//消费滑动
                        offsetX += offset.x
                        offsetY += offset.y
                    })
                },
            contentAlignment = Alignment.Center
        ) {
            Text(text = "轻按滑动圆")
        }
    }

说明

效果

多段滑动

代码

val list = (0..255)

    val width = 300.dp
    val squareSize = 60.dp

    val swipeableState = rememberSwipeableState(0)
    val sizePx = with(LocalDensity.current) { squareSize.toPx() }
    val anchors = mapOf(
        0f to 0,
        sizePx to 1,
        sizePx * 2 to 2,
        sizePx * 3 to 3,
        sizePx * 4 to 4
    ) // Maps anchor points (in px) to states

    Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
        Row(
            Modifier
                .width(width)
                .height(squareSize)) {
            repeat(5) {
                Box(
                    Modifier
                        .width(squareSize)
                        .fillMaxHeight()
                        .background(color = Color(list.random(), list.random(), list.random()))
                )
            }
        }
        Box(
            modifier = Modifier
                .width(width)
                .swipeable(
                    state = swipeableState,
                    anchors = anchors,
                    thresholds = { _, _ -> FractionalThreshold(0.3f) },
                    orientation = Orientation.Horizontal
                )
        ) {
            Box(
                Modifier
                    .offset { IntOffset(swipeableState.offset.value.roundToInt(), 0) }
                    .width(squareSize)
                    .height(200.dp)
                    .background(Color.Yellow)
            ){
                Text(text = "滑动滑块")
            }
        }
    }

说明

这是个实验性质的代码

这里的关键代码如下: 这个anchors会把父容器分为五段,当滑动结束,滑动控件会自动平移到合适的区域位置。

 val anchors = mapOf(
        0f to 0,
        sizePx to 1,
        sizePx * 2 to 2,
        sizePx * 3 to 3,
        sizePx * 4 to 4
    )

效果

双指手势(平移、缩放、旋转)

代码

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.fillMaxSize(), contentAlignment = Alignment.Center) {
        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.Green)
                .fillMaxSize(0.5f),
            contentAlignment = Alignment.Center
        ){
            Text(text = "两指操作,平移,缩放,z轴旋转,单指操作不会有效果", color = Color.White)
        }
    }


说明

效果

嵌套滑动效果

代码

val toolbarHeight = 48.dp//Topbar的高度
    val toolbarHeightPx = with(LocalDensity.current) { toolbarHeight.roundToPx().toFloat() }//topbar高度转换为px
    val toolbarOffsetHeightPx =
        remember { mutableStateOf(0f) }//topbar的动态垂直平移距离
    val nestedScrollConnection = remember {
        object : NestedScrollConnection {
            override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
                val delta = available.y
                val newOffset = toolbarOffsetHeightPx.value + delta//更新topbar的动态平移距离
                toolbarOffsetHeightPx.value = newOffset.coerceIn(-toolbarHeightPx, 0f)//保证topbar的平移距离在(-toolbarHeightPx, 0f)之间
                return Offset.Zero
            }
        }
    }
    Box(
        Modifier
            .fillMaxSize()
            .nestedScroll(nestedScrollConnection)
    ) {
        LazyColumn(contentPadding = PaddingValues(top = toolbarHeight)) {
            items(100) { index ->
                Text("I'm item $index", modifier = Modifier
                    .fillMaxWidth()
                    .padding(16.dp))
            }
        }
        TopAppBar(
            modifier = Modifier
                .height(toolbarHeight)
                .offset { IntOffset(x = 0, y = toolbarOffsetHeightPx.value.roundToInt()) },
            title = { Text("toolbar offset is ${toolbarOffsetHeightPx.value}") }
        )
    }

说明

效果

git地址:github.com/ananananzhu…