Jetpack Compose 似乎专门用于相对于 UI 的其余部分自动定位和调整大小的 UI,而无需知道其确切大小。这在很多情况下都很棒,但我有一些应用程序需要一个可组合项来以精确的像素坐标和大小进行绘制。我还需要跟踪可组合项上的指针输入,以可组合项大小的百分比表示。
我现在正在处理的具体情况是显示一个钢琴键盘,如图所示,其中每个键都需要调整大小并放置在相对于整个键盘的特定位置。另外,我需要跟踪键盘内的指针并计算按下了哪些键。我目前正在使用 Canvas 可组合项来实现它。画布为您提供其大小很有帮助,但我无法在画布范围之外使用该大小来跟踪指针输入。这是我目前的计划。
var width by remember { mutableStateOf(0) }
var height by remember { mutableStateOf(0) }
Canvas(modifier = modifier
.background(Color.Black)
.pointerInput(width, height) {
awaitPointerEventScope {
/* track pointers and calculate which
keys are pressed using the values of
width and height */
}
}.onSizeChanged {
width = it.width
height = it.height
}
) {
/* draw the piano keys, using the values
of size.width and size.height to size and
position them */
}
我的问题是:
首先,如果您不为
Modifier
分配任何大小 Canvas
,则从 size
获得的 DrawScope
将具有 0 宽度和高度。在 Jetpack Compose 中,只要您不需要此尺寸参数,您就可以在任何地方绘制而无需设置它,但如果您检查日志,您会发现它将具有零宽度和高度。
1-您不需要
onSizeChanged
,因为 PointerInputScope
也会返回 size
,这是相同的 size
,除非您在此之后设置任何填充或其他布局修饰符。
如果您想重置pointerInputScope,您可以使用
BoxWithConstraint
as 获取屏幕宽度和高度
@Preview
@Composable
private fun Test() {
BoxWithConstraints(
modifier = Modifier.fillMaxSize()
) {
val width: Dp = maxWidth
val height: Dp = maxHeight
Canvas(
modifier = Modifier.background(Color.Black)
.pointerInput(width, height) {
// The size you get from PointerInputScope is same as you get from
// DrawScope unless you set padding or another layout modifier
val size: IntSize = this.size
awaitPointerEventScope {
/* track pointers and calculate which
keys are pressed using the values of
width and height */
}
}
) {
val size = this.size
println("size: $size")
/* draw the piano keys, using the values
of size.width and size.height to size and
position them */
}
}
}
2- Canvas 是一个带有 Modifier.drawBehind 的 Spacer,在此范围内执行的任何操作都仅调用 google 建议的合成的绘制阶段,尤其是对于动画。
https://developer.android.com/jetpack/compose/performance/bestpractices#defer-reads
查看背景动画片段。