kotlin 全系统屏幕覆盖:在Compose?中创建的可拖动UI元素

ny6fqffe  于 2023-01-17  发布在  Kotlin
关注(0)|答案(1)|浏览(166)

我的目标是有一个小的UI元素(50 dp气泡/方块),可以拖动,并显示在系统屏幕和其他应用程序。是的,像Messenger聊天气泡。
我已经成功地设置了一个ComposeView,并将其与WindowManager一起使用,在其他应用程序上显示。小视图也是可拖动的。
问题是我希望能够将它拖到屏幕上的任何地方,但不阻止方块区域之外的触摸输入。发生阻塞是因为我使用了带有修改符fillMaxSize()的Box。如果我不使用fillMaxSize(),方块在被拖到其初始位置的50 dp x 50 dp区域之外时会被剪切。
这是可组合

@Composable
fun OverlayScreen(
) {
    var offsetX by remember { mutableStateOf(0f) }
    var offsetY by remember { mutableStateOf(0f) }
    Box(
        modifier = Modifier
            .fillMaxSize()
            .offset {
                IntOffset(offsetX.roundToInt(), offsetY.roundToInt())
            }) {
        Box(
            modifier = Modifier
                .height(50.dp)
                .width(50.dp)
                .pointerInput(Unit) {
                    detectDragGestures { change, dragAmount ->
                        change.consume()
                        offsetX += dragAmount.x
                        offsetY += dragAmount.y
                    }
                }
                .background(color = Color(100, 9, 100))

        ) {
            Text("Hello Compose!")
        }
    }
}

这是合成视图:

val bubbleOverlay = ComposeView(context).apply {
            setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
            setContent {
                MaterialTheme {
                    OverlayScreen()
                }
            }
        }

我还启动了前台服务并请求ACTION_MANAGE_OVERLAY_PERMISSION(在其他应用程序上绘制)。

3htmauhk

3htmauhk1#

找到答案了。
您所需要做的就是让Compose处理拖动操作,并将X和Y的拖动量发送到一个函数,该函数将更新View在Window中的位置。
设置布局参数:

mParams = WindowManager.LayoutParams(
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
            WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
            PixelFormat.TRANSLUCENT
        )

创建一个函数来更新视图在窗口中的位置:

private fun moveOverlay(x: Int, y: Int) {
    mParams.x += x
    mParams.y += y
    mWindowManager.updateViewLayout(bubbleOverlay, mParams)
}

将该函数传递给Compose

bubbleOverlay = ComposeView(context).apply {
        setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
        setContent {
            MaterialTheme {
                OverlayScreen(
                    ::moveOverlay
                )
            }
        }
    }

并确保Composable不会填满整个屏幕,因此不要使用fillMaxSize()。

相关问题