Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
package com.example.compose.snippets.graphics

import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeContentPadding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.paint
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.MeshGradientPainter
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp

@Preview
@Composable
fun MeshGradientBasic(modifier: Modifier = Modifier) {
// [START android_compose_graphics_mesh_gradient_basic]
val rows = 1
val columns = 1

val gradientPainter = remember {
MeshGradientPainter(rows, columns) {
// Parameters: row, column, position, color
setVertex(0, 0, Offset(0f, 0f), Color.Red) // Top-Left
setVertex(0, 1, Offset(1f, 0f), Color.Blue) // Top-Right
setVertex(1, 0, Offset(0f, 1f), Color.Green) // Bottom-Left
setVertex(1, 1, Offset(1f, 1f), Color.Yellow) // Bottom-Right
}
}

Box(
modifier = modifier
.aspectRatio(16/9f)
.fillMaxWidth()
.paint(gradientPainter)
)
// [END android_compose_graphics_mesh_gradient_basic]
}

@Preview
@Composable
fun MeshGradientControlPoints(modifier: Modifier = Modifier) {
// [START android_compose_graphics_mesh_gradient_control_points]
val customTangentPainter = remember {
MeshGradientPainter(rows = 1, columns = 1) {
// Tweak the top-left vertex to curve outwards to the right and bottom
setVertex(
row = 0,
column = 0,
position = Offset(0f, 0f),
color = Color.Magenta,
rightControlPoint = Offset(0.4f, 0.1f),
bottomControlPoint = Offset(0.1f, 0.4f)
)

// Other points can remain unspecified to use default inferred fallback tangents
setVertex(0, 1, Offset(1f, 0f), Color.Cyan)
setVertex(1, 0, Offset(0f, 1f), Color.Blue)
setVertex(1, 1, Offset(1f, 1f), Color.Black)
}
}
Box(
modifier = modifier
.aspectRatio(16/9f)
.fillMaxWidth()
.paint(customTangentPainter)
)
// [END android_compose_graphics_mesh_gradient_control_points]
}

@Preview
@Composable
fun MeshGradientComplex(modifier: Modifier = Modifier) {
val purple = Color(0xFFAF52DE)
val indigo = Color(0xFF5856D6)
val yellow = Color(0xFFFFCC00)
val pink = Color(0xFFFF2D55)
val orange = Color(0xFFFF9500)
// [START android_compose_graphics_mesh_gradient_complex]
val points = remember {
listOf(
Offset(0.0f, 0.0f), Offset(0.3f, 0.0f), Offset(0.7f, 0.0f), Offset(1.0f, 0.0f),
Offset(0.0f, 0.3f), Offset(0.2f, 0.4f), Offset(0.7f, 0.2f), Offset(1.0f, 0.3f),
Offset(0.0f, 0.7f), Offset(0.3f, 0.8f), Offset(0.7f, 0.6f), Offset(1.0f, 0.7f),
Offset(0.0f, 1.0f), Offset(0.3f, 1.0f), Offset(0.7f, 1.0f), Offset(1.0f, 1.0f)
)
}

val gradientPainter = remember {
MeshGradientPainter(rows = 3, columns = 3) {
// Row 0
setVertex(0, 0, points[0], yellow)
setVertex(0, 1, points[1], orange)
setVertex(0, 2, points[2], yellow)
setVertex(0, 3, points[3], purple)

// Row 1
setVertex(1, 0, points[4], pink)
setVertex(1, 1, points[5], yellow)
setVertex(1, 2, points[6], pink)
setVertex(1, 3, points[7], purple)

// Row 2
setVertex(2, 0, points[8], indigo)
setVertex(2, 1, points[9], pink)
setVertex(2, 2, points[10], purple)
setVertex(2, 3, points[11], indigo)

// Row 3
setVertex(3, 0, points[12], purple)
setVertex(3, 1, points[13], indigo)
setVertex(3, 2, points[14], pink)
setVertex(3, 3, points[15], yellow)
}
}

Box(
modifier = modifier.padding(32.dp)
.aspectRatio(16 / 9f)
.fillMaxWidth()
.paint(gradientPainter)
// [START_EXCLUDE]
.drawWithContent {
drawContent()
points.forEach { normalizedOffset ->
val pixelOffset = Offset(
x = normalizedOffset.x * size.width,
y = normalizedOffset.y * size.height
)
// Draw a subtle black circle outline and white center for maximum visibility
drawCircle(
color = Color.Black,
radius = 10f,
center = pixelOffset
)
drawCircle(
color = Color.White,
radius = 8f,
center = pixelOffset
)
}
}
// [END_EXCLUDE]
)
// [END android_compose_graphics_mesh_gradient_complex]
}

@Preview
@Composable
fun MeshGradientAnimation(modifier: Modifier = Modifier) {
// [START android_compose_graphics_mesh_gradient_animation]
val infiniteTransition = rememberInfiniteTransition(label = "meshMovement")
val animatedOffset by infiniteTransition.animateFloat(
initialValue = -0.1f,
targetValue = 0.1f,
animationSpec = infiniteRepeatable(
animation = tween(2500, easing = LinearEasing),
repeatMode = RepeatMode.Reverse
),
label = "offset"
)

val coral = Color(255, 90, 90)
val peach = Color(255, 139, 90)
val amber = Color(255, 169, 90)
val sunshine = Color(255, 212, 90)
val indigo = Color(0xFF5856D6)
val pink = Color(0xFFFF2D55)


val gradientPainter = remember {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The gradientPainter is remembered without any keys, but its builder block captures and reads the animatedOffset state. Because remember without keys only runs once during initial composition, the painter will not be recreated or updated when animatedOffset changes, causing the gradient to remain completely static. Adding animatedOffset as a key to remember ensures the painter is updated/recreated as the animation progresses.

Suggested change
val gradientPainter = remember {
val gradientPainter = remember(animatedOffset) {

MeshGradientPainter(rows = 3, columns = 3) {
// Row 0
setVertex(0, 0, Offset(0.0f, 0.0f), indigo)
setVertex(0, 1, Offset(0.3f, 0.0f), peach)
setVertex(0, 2, Offset(0.7f, 0.0f), amber)
setVertex(0, 3, Offset(1.0f, 0.0f), sunshine)
// Row 1
setVertex(1, 0, Offset(0.0f, 0.3f), pink)
setVertex(1, 1, Offset(0.2f, 0.4f) + Offset(animatedOffset, animatedOffset), coral)
setVertex(1, 2, Offset(0.7f, 0.2f) + Offset(animatedOffset, animatedOffset), peach)
setVertex(1, 3, Offset(1.0f, 0.3f), indigo)

// Row 2
setVertex(2, 0, Offset(0.0f, 0.7f), coral)
setVertex(2, 1, Offset(0.3f, 0.8f) + Offset(animatedOffset, 0f), pink)
setVertex(2, 2, Offset(0.7f, 0.6f) + Offset(animatedOffset, 0f), sunshine)
setVertex(2, 3, Offset(1.0f, 0.7f), amber)

// Row 3
setVertex(3, 0, Offset(0.0f, 1.0f), sunshine)
setVertex(3, 1, Offset(0.3f, 1.0f), amber)
setVertex(3, 2, Offset(0.7f, 1.0f), pink)
setVertex(3, 3, Offset(1.0f, 1.0f), indigo)
}
}


Box(
modifier = modifier.padding(32.dp)
.safeContentPadding()
.aspectRatio(16 / 9f)
.fillMaxWidth()
.paint(gradientPainter)
)
// [END android_compose_graphics_mesh_gradient_animation]
}
4 changes: 2 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ androidx-appcompat = "1.7.1"
androidx-appfunctions = "1.0.0-alpha08"
androidx-cameraX = "1.6.0"
androidx-car = "1.7.0"
androidx-compose-bom = "2026.05.00"
androidx-compose-bom = "2026.05.01"
androidx-compose-ui-test = "1.7.0-alpha08"
androidx-compose-ui-test-junit4-accessibility = "1.11.1"
androidx-constraintlayout = "2.2.1"
Expand Down Expand Up @@ -140,7 +140,7 @@ androidx-camera-viewfinder-compose = { module = "androidx.camera.viewfinder:view
androidx-camera-camera2 = { module = "androidx.camera:camera-camera2", version.ref = "androidx-cameraX" }
androidx-car = { module = "androidx.car.app:app", version.ref = "androidx-car"}
androidx-compose-animation-graphics = { module = "androidx.compose.animation:animation-graphics", version.ref = "compose-latest" }
androidx-compose-bom = { module = "androidx.compose:compose-bom", version.ref = "androidx-compose-bom" }
androidx-compose-bom = { module = "androidx.compose:compose-bom-alpha", version.ref = "androidx-compose-bom" }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it okay move the whole repo to alpha?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kkuan2011 no, will leave this as a branch until we are good to go with a stable version :)

@kkuan2011 kkuan2011 Jun 6, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok sounds good :) I'll assume no action needed for now then

androidx-compose-foundation = { module = "androidx.compose.foundation:foundation", version.ref = "compose-latest" }
androidx-compose-foundation-layout = { module = "androidx.compose.foundation:foundation-layout", version.ref = "compose-latest" }
androidx-compose-material = { module = "androidx.compose.material:material", version.ref = "compose-latest" }
Expand Down
2 changes: 1 addition & 1 deletion wearcompanion/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ plugins {

android {
namespace = "com.example.wear.snippets"
compileSdk = 36
compileSdk = 37

defaultConfig {
applicationId = "com.example.wear.snippets"
Expand Down
Loading