Android compose:实现一个拖拽、自动贴边的控件

304 阅读1分钟
@Composable
private fun DraggableFree() {
    val canvasWidth = 360.dp//画布大小
    val canvasHeight = 200.dp
    val blockSize = 50.dp//拖动方块大小
    val maxOffsetX = with(LocalDensity.current) { (canvasWidth - blockSize).toPx() }//最大可移动的X轴偏移量
    val maxOffsetY = with(LocalDensity.current) { (canvasHeight - blockSize).toPx() }//最大可移动的Y轴偏移量

    Box(modifier = Modifier.size(canvasWidth, canvasHeight)) {
        var offsetX by remember { mutableFloatStateOf(0f) }
        var offsetY by remember { mutableFloatStateOf(0f) }
        val scope = rememberCoroutineScope()
        Box(
            Modifier
                .offset { IntOffset(offsetX.roundToInt(), offsetY.roundToInt()) }
                .size(blockSize)
                .background(Color.Blue)
                .pointerInput(Unit) {
                    detectDragGestures(onDragEnd = {
                        val endOffsetX = if (offsetX > maxOffsetX / 2) maxOffsetX else 0f//计算拖动结束动画停留的位置
                        scope.launch {
                            Animatable(offsetX).animateTo(endOffsetX, animationSpec = tween(durationMillis = 300, easing = LinearEasing)) {
                                offsetX = this.value
                            }
                        }
                    }) { change, dragAmount ->
                        offsetX = (offsetX + dragAmount.x).coerceIn(0f, maxOffsetX)//限制拖动范围
                        offsetY = (offsetY + dragAmount.y).coerceIn(0f, maxOffsetY)
                        change.consume()
                    }
                }
                .clickableNoRipple {
                    showToast("我被点击了")
                }
        ) {
            //content
        }
    }
}