Build apps faster with our new App builder! Check it out →

drawWithCache

Common

Modifier in Compose Ui

Draw into a [DrawScope] with content that is persisted across draw calls as long as the size of the drawing area is the same or any state objects that are read have not changed. In the event that the drawing area changes, or the underlying state values that are being read change, this method is invoked again to recreate objects to be used during drawing

For example, a [androidx.compose.ui.graphics.LinearGradient] that is to occupy the full bounds of the drawing area can be created once the size has been defined and referenced for subsequent draw calls without having to re-allocate.

Last updated:

Installation

dependencies {
   implementation("androidx.compose.ui:ui:1.8.0-alpha04")
}

Overloads


fun Modifier.drawWithCache(onBuildDrawCache: CacheDrawScope.() -> DrawResult)

Code Examples

DrawWithCacheModifierSample

/**
 * Sample showing how to leverage [Modifier.drawWithCache] in order to cache contents in between
 * draw calls that depend on sizing information. In the example below, the LinearGradient is created
 * once and re-used across calls to onDraw. If the size of the drawing area changes, then the
 * LinearGradient is re-created with the updated width and height.
 */
@Composable
fun DrawWithCacheModifierSample() {
    Box(
        Modifier.drawWithCache {
            val gradient =
                Brush.linearGradient(
                    colors = listOf(Color.Red, Color.Blue),
                    start = Offset.Zero,
                    end = Offset(size.width, size.height)
                )
            onDrawBehind { drawRect(gradient) }
        }
    )
}

DrawWithCacheModifierStateParameterSample

/**
 * Sample showing how to leverage [Modifier.drawWithCache] to persist data across draw calls. In the
 * example below, the linear gradient will be re-created if either the size of the drawing area
 * changes, or the toggle flag represented by a mutable state object changes. Otherwise the same
 * linear gradient instance is re-used for each call to drawRect.
 */
@Composable
fun DrawWithCacheModifierStateParameterSample() {
    val colors1 = listOf(Color.Red, Color.Blue)
    val colors2 = listOf(Color.Yellow, Color.Green)
    var toggle by remember { mutableStateOf(true) }
    Box(
        Modifier.clickable { toggle = !toggle }
            .drawWithCache {
                val gradient =
                    Brush.linearGradient(
                        colors = if (toggle) colors1 else colors2,
                        start = Offset.Zero,
                        end = Offset(size.width, size.height)
                    )
                onDrawBehind { drawRect(gradient) }
            }
    )
}

DrawWithCacheContentSample

/**
 * Sample showing how to leverage [Modifier.drawWithCache] to cache a LinearGradient if the size is
 * unchanged. Additionally this sample illustrates how to re-arrange drawing order using
 * [ContentDrawScope.drawContent] in order to draw the desired content first to support blending
 * against the sample vector graphic of a triangle
 */
@Composable
fun DrawWithCacheContentSample() {
    val vectorPainter =
        rememberVectorPainter(24.dp, 24.dp, autoMirror = true) { viewportWidth, viewportHeight ->
            Path(
                pathData =
                    PathData {
                        lineTo(viewportWidth, 0f)
                        lineTo(0f, viewportHeight)
                        close()
                    },
                fill = SolidColor(Color.Black)
            )
        }
    Image(
        painter = vectorPainter,
        contentDescription = null,
        modifier =
            Modifier.requiredSize(120.dp).drawWithCache {
                val gradient =
                    Brush.linearGradient(
                        colors = listOf(Color.Red, Color.Blue),
                        start = Offset.Zero,
                        end = Offset(0f, size.height)
                    )
                onDrawWithContent {
                    drawContent()
                    drawRect(gradient, blendMode = BlendMode.Plus)
                }
            }
    )
}
by @alexstyl