Android compose 让组件可随意拖动,并限制在屏幕范围内

180 阅读1分钟
//让组件可随意拖动,并限制在屏幕范围内
fun Modifier.draggableView() = composed {
    val boxRect = remember { mutableStateOf(Rect.Zero) }
    val offset = remember { mutableStateOf(Offset.Zero) }
    val context = LocalContext.current
    val isRtl = LocalLayoutDirection.current == LayoutDirection.Rtl
    val scale = if (isRtl) -1f else 1f
    val screenWidth = remember {
        context.resources.displayMetrics.widthPixels
    }
    val screenHeight = remember {
        context.resources.displayMetrics.heightPixels
    }
    this
        .offset { IntOffset(offset.value.x.roundToInt(), offset.value.y.roundToInt()) }
        .onGloballyPositioned { coordinates ->
            if (boxRect.value == Rect.Zero) {
                boxRect.value = coordinates.boundsInWindow()
            }
        }
        .pointerInput(Unit) {
            detectTransformGestures(
                panZoomLock = false, // 平移或放大时是否可以旋转
                onGesture = { centroid: Offset, pan: Offset, zoom: Float, rotation: Float ->
                    val offsetX = offset.value.x * scale
                    val offsetY = offset.value.y
                    val x = boxRect.value.left + offsetX
                    val y = boxRect.value.top + offsetY
                    var targetX = x + pan.x
                    var targetY = y + pan.y
                    if (targetX < 0f) {
                        targetX = 0f
                    }
                    if (targetX > screenWidth - boxRect.value.width) {
                        targetX = screenWidth - boxRect.value.width
                    }
                    if (targetY < 0f) {
                        targetY = 0f
                    }
                    if (targetY > screenHeight - boxRect.value.height) {
                        targetY = screenHeight - boxRect.value.height
                    }
                    offset.value += Offset((targetX - x) * scale, targetY - y)
                }
            )
        }
}