何时初始化要在 Compose Canvas 中使用的资源?
When to initialize resources to be used inside Compose Canvas?
我正在使用 Jetpack Compose,我想创建一个带有自定义 shadow/gradient 效果的圆圈。据我所知,无法使用 DrawScope
内的可组合对象来创建它,我必须改用 NativeCanvas
。这对我的情况来说很好,但我记得当我们使用 View 并在 onDraw()
方法中写一些东西时,我们不应该在那里初始化新对象。由于在使用动画时每 30/60fps 调用该方法并为每次调用创建新对象将导致性能不佳。
定义这些对象 BlurMaskFilter
、RadialGradient
、Paint
的正确位置在哪里,以便仅当可组合项的大小发生变化时才可以重新初始化它们?
我想知道是否应该在函数外定义它们为 lateinit var
然后使用 SideEffect
来初始化它们?
我忘了说我正在使用 InfiniteTransition
,然后使用状态更改 NativeCanvas
!
中绘制的形状
Box(
modifier = Modifier
.size(widthDp, widthDp)
.drawBehind {
drawIntoCanvas { canvas ->
canvas.nativeCanvas.apply {
val blurMask = BlurMaskFilter(
15f,
BlurMaskFilter.Blur.NORMAL
)
val radialGradient = android.graphics.RadialGradient(
100f, 100f, 50f,
intArrayOf(android.graphics.Color.WHITE, android.graphics.Color.BLACK),
floatArrayOf(0f, 0.9f), android.graphics.Shader.TileMode.CLAMP
)
val paint = Paint().asFrameworkPaint().apply {
shader = radialGradient
maskFilter = blurMask
color = android.graphics.Color.WHITE
}
drawCircle(100f, 100f, 50f, paint)
}
}
}
) {
}
有两种方法可以在 Compose 中的重组之间保留一些对象 - 使用 remember
或表示模型。对于这种特殊情况,remember
更合适。
如果你有Modifier.size(widthDp, widthDp)
给定的静态尺寸,提前计算一切就很容易了:
val density = LocalDensity.current
val paint = remember(widthDp) {
// in case you need to use width in your calculations
val widthPx = with(density) {
widthDp.toPx()
}
val blurMask = BlurMaskFilter(
15f,
BlurMaskFilter.Blur.NORMAL
)
val radialGradient = android.graphics.RadialGradient(
100f, 100f, 50f,
intArrayOf(android.graphics.Color.WHITE, android.graphics.Color.BLACK),
floatArrayOf(0f, 0.9f), android.graphics.Shader.TileMode.CLAMP
)
Paint().asFrameworkPaint().apply {
shader = radialGradient
maskFilter = blurMask
color = android.graphics.Color.WHITE
}
}
如果你没有静态尺寸,例如你想使用 Modifier.fillMaxSize
,你可以使用 Modifier.onSizeChanged
来获取实际尺寸并更新你的 Paint
- 那是为什么我在 remember
调用中将 size
作为 key
传递 - 它会在 key
更改时重新计算值。
val (size, updateSize) = remember { mutableStateOf<IntSize?>(null) }
val paint = remember(size) {
if (size == null) {
Paint()
} else {
Paint().apply {
// your code
}
}
}
Box(
modifier = Modifier
.fillMaxSize()
.onSizeChanged(updateSize)
.drawBehind {
// ...
}
)
我正在使用 Jetpack Compose,我想创建一个带有自定义 shadow/gradient 效果的圆圈。据我所知,无法使用 DrawScope
内的可组合对象来创建它,我必须改用 NativeCanvas
。这对我的情况来说很好,但我记得当我们使用 View 并在 onDraw()
方法中写一些东西时,我们不应该在那里初始化新对象。由于在使用动画时每 30/60fps 调用该方法并为每次调用创建新对象将导致性能不佳。
定义这些对象 BlurMaskFilter
、RadialGradient
、Paint
的正确位置在哪里,以便仅当可组合项的大小发生变化时才可以重新初始化它们?
我想知道是否应该在函数外定义它们为 lateinit var
然后使用 SideEffect
来初始化它们?
我忘了说我正在使用 InfiniteTransition
,然后使用状态更改 NativeCanvas
!
Box(
modifier = Modifier
.size(widthDp, widthDp)
.drawBehind {
drawIntoCanvas { canvas ->
canvas.nativeCanvas.apply {
val blurMask = BlurMaskFilter(
15f,
BlurMaskFilter.Blur.NORMAL
)
val radialGradient = android.graphics.RadialGradient(
100f, 100f, 50f,
intArrayOf(android.graphics.Color.WHITE, android.graphics.Color.BLACK),
floatArrayOf(0f, 0.9f), android.graphics.Shader.TileMode.CLAMP
)
val paint = Paint().asFrameworkPaint().apply {
shader = radialGradient
maskFilter = blurMask
color = android.graphics.Color.WHITE
}
drawCircle(100f, 100f, 50f, paint)
}
}
}
) {
}
有两种方法可以在 Compose 中的重组之间保留一些对象 - 使用 remember
或表示模型。对于这种特殊情况,remember
更合适。
如果你有Modifier.size(widthDp, widthDp)
给定的静态尺寸,提前计算一切就很容易了:
val density = LocalDensity.current
val paint = remember(widthDp) {
// in case you need to use width in your calculations
val widthPx = with(density) {
widthDp.toPx()
}
val blurMask = BlurMaskFilter(
15f,
BlurMaskFilter.Blur.NORMAL
)
val radialGradient = android.graphics.RadialGradient(
100f, 100f, 50f,
intArrayOf(android.graphics.Color.WHITE, android.graphics.Color.BLACK),
floatArrayOf(0f, 0.9f), android.graphics.Shader.TileMode.CLAMP
)
Paint().asFrameworkPaint().apply {
shader = radialGradient
maskFilter = blurMask
color = android.graphics.Color.WHITE
}
}
如果你没有静态尺寸,例如你想使用 Modifier.fillMaxSize
,你可以使用 Modifier.onSizeChanged
来获取实际尺寸并更新你的 Paint
- 那是为什么我在 remember
调用中将 size
作为 key
传递 - 它会在 key
更改时重新计算值。
val (size, updateSize) = remember { mutableStateOf<IntSize?>(null) }
val paint = remember(size) {
if (size == null) {
Paint()
} else {
Paint().apply {
// your code
}
}
}
Box(
modifier = Modifier
.fillMaxSize()
.onSizeChanged(updateSize)
.drawBehind {
// ...
}
)