Last active
April 14, 2024 19:20
-
-
Save nirbhayph/2be482a269a4b7098dfba78ef8d597a4 to your computer and use it in GitHub Desktop.
Delving into Canvas for Custom Graphics and Animations with Jetpack Compose
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Composable | |
fun Chart(){ | |
val temperatureData = listOf( | |
DataPoint(20f, SampleColors.lighterPink), | |
DataPoint(45f, SampleColors.lightBlue), | |
DataPoint(130f, SampleColors.darkPink), | |
DataPoint(80f, SampleColors.lightPink), | |
DataPoint(65f, Color.Cyan) | |
) | |
BarChart(data = temperatureData) | |
} | |
data class DataPoint(val value: Float, val color: Color) | |
@Composable | |
fun BarChart(data: List<TemperaturePoint>) { | |
val maxBarValue = data.maxOf { it.value } | |
Canvas( | |
modifier = Modifier.fillMaxSize() | |
.background(Brush | |
.horizontalGradient( | |
listOf( | |
Color.White, | |
Color.Red, | |
Color.Yellow)) | |
.padding(20.dp) | |
) { | |
val maxBarHeight = size.height | |
val barWidth = size.width / data.size | |
data.forEachIndexed { index, dataPoint -> | |
val barHeight = (dataPoint.value / maxBarValue) * maxBarHeight | |
drawRect( | |
color = dataPoint.color, | |
topLeft = Offset(index * barWidth, size.height - barHeight), | |
size = Size(barWidth, barHeight) | |
) | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Composable | |
fun BouncingBallGame() { | |
val position = remember { mutableStateOf(Offset(300f, 0f)) } | |
val velocity = remember { mutableStateOf(Offset(3f, 3f)) } | |
LaunchedEffect(Unit) { | |
while (true) { | |
position.value += velocity.value | |
// change > condition to size of screen, | |
// here just using a static value for demo purposes | |
if (position.value.x < 0f || position.value.x > 1000f) { | |
velocity.value = Offset(-velocity.value.x, velocity.value.y) | |
} | |
if (position.value.y < 0f || position.value.y > 1200f) { | |
velocity.value = Offset(velocity.value.x, -velocity.value.y) | |
} | |
delay(16L) | |
} | |
} | |
Column( | |
modifier = Modifier.background( | |
brush = Brush.horizontalGradient( | |
listOf( | |
Color.Red, | |
Color.Blue | |
) | |
) | |
) | |
) { | |
Canvas( | |
modifier = Modifier | |
.height(460.dp) | |
.fillMaxWidth() | |
) { | |
drawCircle( | |
brush = Brush.horizontalGradient(listOf(Color.Blue, Color.Red)), | |
center = position.value, | |
radius = 60f | |
) | |
} | |
Divider(thickness = 5.dp, color = Color.Red) | |
Column( | |
modifier = Modifier.fillMaxSize(), | |
horizontalAlignment = Alignment.CenterHorizontally, | |
verticalArrangement = Arrangement.Center | |
) { | |
Button( | |
colors = ButtonDefaults.buttonColors(containerColor = Color.Red), | |
onClick = { | |
val random = (-1..1).random() | |
if (random != 0) { | |
velocity.value += Offset(random * 10f, random * 10f) | |
} | |
}, | |
) { | |
Text(text = "Change Bounce") | |
} | |
Text( | |
text = "Velocity: ${velocity.value.x}, ${velocity.value.y}", | |
color = Color.White, | |
) | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Composable | |
fun CanvasShapesAndPaths(){ | |
Canvas( | |
modifier = Modifier | |
.fillMaxSize() | |
.background(SampleColors.lighterPink) | |
.padding(10.dp)) { | |
// Draw a rectangle | |
drawRect(color = SampleColors.lightPink) | |
// Draw a circle | |
drawCircle(color = SampleColors.darkPink, radius = 400f) | |
// Draw a custom path | |
val path = Path().apply { | |
moveTo(600f, 1200f) | |
lineTo(800f, 800f) | |
lineTo(350f, 400f) | |
lineTo(160f, 25f) | |
close() | |
} | |
drawPath( | |
path = path, | |
brush = Brush.horizontalGradient( | |
listOf( | |
SampleColors.lightBlue, | |
SampleColors.lighterPink | |
) | |
) | |
) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import androidx.compose.foundation.Canvas | |
@Composable | |
fun CustomCanvasExample() { | |
Canvas( | |
modifier = Modifier.fillMaxSize() | |
) { | |
// Your drawing code here | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Composable | |
fun MovingCircles() { | |
val position = remember { Animatable(0f) } | |
LaunchedEffect(Unit) { | |
position.animateTo( | |
targetValue = 550f, | |
animationSpec = tween(durationMillis = 3000) | |
) | |
} | |
Canvas( | |
modifier = Modifier.fillMaxSize().background(Color.Black) | |
) { | |
drawCircle(color = Color.Red, center = Offset(position.value, 500f), radius = 50f) | |
drawCircle(color = Color.Blue, center = Offset(position.value, 700f), radius = 80f) | |
drawCircle(color = Color.Magenta, center = Offset(position.value, 1000f), radius = 150f) | |
drawCircle(color = Color.Yellow, center = Offset(position.value, 1400f), radius = 190f) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
override fun onCreate(savedInstanceState: Bundle?) { | |
super.onCreate(savedInstanceState) | |
setContent { | |
val particlesData = listOf<Particle>( | |
Particle(Offset(100f, 1820f), Offset(1f, -2f)), | |
Particle(Offset(200f, 1680f), Offset(-0.5f, -1.5f)), | |
Particle(Offset(300f, 1700f), Offset(0.2f, -1.8f)), | |
Particle(Offset(400f, 1850f), Offset(-0.8f, -2f)), | |
Particle(Offset(500f, 1800f), Offset(0.4f, -1.2f)), | |
Particle(Offset(600f, 1960f), Offset(1f, -2f)), | |
Particle(Offset(700f, 1980f), Offset(-0.5f, -1.5f)), | |
Particle(Offset(800f, 2010f), Offset(0.2f, -1.8f)), | |
Particle(Offset(900f, 1950f), Offset(-0.8f, -2f)), | |
Particle(Offset(750f, 2000f), Offset(0.4f, -1.2f)), | |
Particle(Offset(100f, 1780f), Offset(1f, -2f)), | |
Particle(Offset(200f, 1790f), Offset(-0.5f, -1.5f)), | |
Particle(Offset(300f, 1805f), Offset(0.2f, -1.8f)), | |
Particle(Offset(400f, 1815f), Offset(-0.8f, -2f)), | |
Particle(Offset(500f, 1825f), Offset(0.4f, -1.2f)), | |
Particle(Offset(600f, 1915f), Offset(1f, -2f)), | |
Particle(Offset(700f, 1922f), Offset(-0.5f, -1.5f)), | |
Particle(Offset(800f, 2014f), Offset(0.2f, -1.8f)), | |
Particle(Offset(900f, 2012f), Offset(-0.8f, -2f)), | |
Particle(Offset(750f, 2004f), Offset(0.4f, -1.2f)) | |
) | |
ParticleSystem(particlesData) | |
} | |
} | |
data class Particle( | |
val position: Offset, | |
val velocity: Offset | |
) | |
@Composable | |
fun ParticleSystem(particles: List<Particle>) { | |
val mutableParticles = remember { mutableStateListOf<Particle>() } | |
mutableParticles.addAll(particles) | |
var counter = 0 | |
LaunchedEffect(Unit) { | |
while (true) { | |
val particlesCopy = ArrayList(mutableParticles.map { it.copy() }) | |
particlesCopy.forEachIndexed { index, particle -> | |
mutableParticles[index] = | |
particle.copy(position = particle.position + particle.velocity) | |
} | |
delay(16L) | |
counter += 1 | |
// modify as needed or change the condition to something like | |
// when all particles are out of bounds of the screen | |
if (counter > 3000) { | |
break | |
} | |
} | |
} | |
Canvas( | |
modifier = Modifier | |
.fillMaxSize() | |
.background(Brush.horizontalGradient(listOf(SampleColors.yellow, SampleColors.gold))) | |
) { | |
mutableParticles.forEach { particle -> | |
drawCircle(color = SampleColors.brown, alpha = 0.6F, center = particle.position, radius = 10f) | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import androidx.compose.ui.graphics.Color | |
object SampleColors { | |
val lightPink = Color(0xFFB86Fff) | |
val lightBlue = Color(0xF194B4ff) | |
val darkPink = Color(0xFFB100ff) | |
val lighterPink = Color(0xFFEBC6ff) | |
val gold = Color(0xffFDC00D) | |
val yellow = Color(0xffFDF56E) | |
val brown = Color(0xffA17800) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi, have you faced any problem with the bouncy ball when you have been a lot of time? because I have somethiing similiar and my screen freezes when i have been a lot of time.