Draw Animated Circle in Android
Hey people ! Welcome to my weblog on animating custom shapes, pulsating circles, draw shapes on sail and breathing them with compose.
This is the preview of what we will build. Let's go started.
You can take reference of the source lawmaking from GitHub repository and above preview image is for the app which I will take equally an example.
Dependency
Right now I'grand using compose version 1.0.5 which is latest release.
implementation "androidx.compose.ui:ui:$compose_version" implementation "androidx.compose.runtime:runtime-livedata:$compose_version" 1. Animate circle on canvas
First we will breathing circle on canvas using drawArc().
This is how it should look.
We have to think the initial float value in Animatable function that automatically animates its value.
val animateCircle = remember { Animatable(0f) } In composable nosotros launch coroutine with LaunchedEffect and animate the shape.
animateTo will starts an blitheness to animate from value to the provided targetValue.
LaunchedEffect(animateCircle) { animateCircle.animateTo( targetValue = onef, animationSpec = infiniteRepeatable( animation = tween( durationMillis = 1000, easing = LinearEasing ), repeatMode = RepeatMode.Restart ) ) } Blitheness properties
- animateValue – Breathing from initial (0f) to target (1f) value.
- infiniteRepeatable – Creates elapsing based animation for space amount of times.
- tween – Animation type, alternative is jump, keyframes.
- durationMillis – Fourth dimension taken for one animation cycle to consummate.
- easing – Default is FastOutSlowInEasing, easing is but interpolation.
- repeatMode – Default is Restart, whether animation should brainstorm from end or kickoff(Reverse)
Now lets use drawArc() to draw animated circumvolve on canvas.
Canvas( modifier = Modifier ) { drawArc( color = Color(0xFF302522), startAngle = 45f, sweepAngle = 360f * animateCircle.value, useCenter = false, size = Size(80f, 80f), style = Stroke(16f, cap = StrokeCap.Round) ) } drawArc( ) properties
- drawArc – Draws an arc scaled to fit inside the given rectangle.
- color – Colour to be applied to the arc
- startAngle – 0 represents three o'clock. We will start at 45 -> 4:30.
- sweepAngle – We provide 360f to form full circumvolve.
- useCenter – I kept information technology false because I don't want a sector to form.
- size – Size taken past arc in canvas.
- style – DrawStyle default is Fill, I kept it stroke with 16 width and rounded.
At this a circle with edge volition be fatigued on canvas, but nosotros desire its path to exist animated from initial to target value, for that we accept to pass the initial value to the drawArc() while information technology starts laying on Sheet.
We can multiply the initial bladder value with sweepAngle while information technology draws the arc. This will lay the arc with the progressive looking circle in canvas or like a loading round progress bar.
drawArc( sweepAngle = 360f * animateCircle.value ) Here'due south the combined code changes from to a higher place to animate circle.
@Composable fun AnimateCircle () { val animateCircle = call back { Animatable(0f) } Box( modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center ) { LaunchedEffect(animateCircle) { animateCircle.animateTo( targetValue = anef, animationSpec = infiniteRepeatable( animation = tween( durationMillis = 1000, easing = LinearEasing ), repeatMode = RepeatMode.Restart ) ) } Canvas( modifier = Modifier ) { drawArc( color = Color(0xFF302522), startAngle = 45f, sweepAngle = 360f * animateCircle.value, useCenter = false, size = Size(80f, 80f), manner = Stroke(sixteenf, cap = StrokeCap.Round) ) } } } Check whether your circle is animating equally expected compared to my above preview. Now let'due south move to animating a simple line.
2. Animate line on sheet
This is what we should try to animate, line expands and moves to target float.
Cipher changes much as compared to previous.
- Need a new Animatable property with dissimilar initial float value.
- Properties for blitheness remains same except initial float value.
- To animate line we will use drawLine().
We have to remember the initial float value in Animatable office that automatically animates its value.
val animateLine = recollect { Animatable(0.6f) } Launch coroutine and animate line with LaunchedEffect.
LaunchedEffect(animateLine) { animateLine.animateTo( targetValue = onef, animationSpec = infiniteRepeatable( animation = tween( durationMillis = k, easing = LinearEasing ), repeatMode = RepeatMode.Restart ) ) } I'm using initial value 0.6f to reduce floating fourth dimension of line to reach it's concluding land. Setting it to 0f volition make final animation output to look kind of aggressive. Change its value for your convenience.
Now draw a line on Sheet with drawLine().
Line has start and end offset points. So give (ten, y) first and stop offsets to line. Also multiply those offsets x, y with initial bladder value for animation to start.
drawLine( colour = Color(0xFF302522), strokeWidth = xvif, cap = StrokeCap.Round, showtime = Kickoff( 80f * animateLine.value, 80f * animateLine.value ), end = Start( 110f * animateLine.value, 110f * animateLine.value ) ) Combine circle and line
Brining all the changes in single composable, since we are using same animationSpec properties, nosotros can reuse it by moving to split up composable.
fun AnimateShapeInfinitely ( animatableShape: Animatable<Float, AnimationVector1D> ) { LaunchedEffect(animatableShape) { animatableShape.animateTo( targetValue = 1f, animationSpec = infiniteRepeatable( animation = tween( durationMillis = 1000, easing = LinearEasing ), repeatMode = RepeatMode.Restart ) ) } } Finally this composable role draws circle and line in single canvas.
At this point you should be able to see both line and circumvolve border animation.
@Composable fun AnimateSearch () { val animateCircle = remember { Animatable(0f) }.apply { AnimateShapeInfinitely(this) } val animateLine = call up { Animatable(0.6f) }.apply { AnimateShapeInfinitely(this) } Box( modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center ) { Canvas( modifier = Modifier ) { drawArc( colour = Color(0xFF302522), startAngle = 45f, sweepAngle = 360f * animateCircle.value, useCenter = false, size = Size(80f, fourscoref), mode = Stroke(16f, cap = StrokeCap.Round) ) drawLine( color = Colour(0xFF302522), strokeWidth = 16f, cap = StrokeCap.Round, outset = Offset( animateLine.value * 80f, animateLine.value * 80f ), finish = Start( animateLine.value * 110f, animateLine.value * 110f ) ) } } } We have completed animating search expect-a-like shape.
three. Pulsating circumvolve animation
This is what we desire to create.
Let's showtime by drawing a circumvolve in canvas.
Canvas( modifier = Modifier.fillMaxSize() ) { val canvasWidth = size.width val canvasHeight = size.height drawCircle( color = Colour(0xFFffb59c), center = Starting time( 10 = canvasWidth / 2, y = canvasHeight / 2 ), radius = size.minDimension / 4f, ) } GraphicsLayer
From Android Documentation
Tin can be used to apply effects to content, such every bit scaling, rotation, opacity, shadow, and clipping. Prefer this version when you lot have layer properties or an animated value.
Canvass modifier allows us to employ graphics scale properties. Just we likewise want to animate the scaling of the circle on canvas betwixt initial and target float values. And so we should use animateFloat and create a infinite transition.
Create a InfiniteTransition that runs space child animations. Kid animations will start running as soon equally they enter the composition, and will not terminate until they are removed from the composition.
val infiniteTransition = rememberInfiniteTransition() With space transition you can animate float changes.
val scale by infiniteTransition.animateFloat( initialValue = 0f, targetValue = i.2f, animationSpec = infiniteRepeatable( animation = tween( durationMillis = 600, easing = LinearEasing ), repeatMode = RepeatMode.Contrary ) ) - initialValue – Bladder value where the animations starts.
- targetValue – Final float value where animation ends.
- infiniteRepeatable – Animations that plays infinite amount of times.
Now use that calibration float value graphics layer of sheet.
Canvass( modifier = Modifier .fillMaxSize() .graphicsLayer { scaleX = calibration scaleY = scale } ) These are the terminal changes for unmarried pulsating circle on canvas.
@Composable fun PulsatingCircle () { Box( modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Eye ) { val infiniteTransition = rememberInfiniteTransition() val calibration by infiniteTransition.animateFloat( initialValue = 0f, targetValue = 1.2f, animationSpec = infiniteRepeatable( animation = tween( durationMillis = 600, easing = LinearEasing ), repeatMode = RepeatMode.Reverse ) ) Canvass( modifier = Modifier .fillMaxSize() .graphicsLayer { scaleX = scale scaleY = scale } ) { val canvasWidth = size.width val canvasHeight = size.peak drawCircle( color = Color(0xFFffb59c), center = Outset( x = canvasWidth / 2, y = canvasHeight / 2 ), radius = size.minDimension / 4f, ) } } } Now allow'south add 2 more circles with sail.
4. Infinite repeatable pulsating animation
Equally shown in preview, we need 3 circles full with different animationSpec properties. This mode nosotros can make sure that the 3 circles won't look same. And then nosotros will pass unlike values for below properties.
- Target float value
- Circle groundwork color
- Blitheness duration
- Radius ratio
Let the states create a reusable composable for iii circles for infinite transition with role name scaleInfiniteTransition.
I accept kept all initial states of 3 circles to 0f to make end result much smoother. Random or uneven gaps between initial, target, durationMillis volition make finish animation wait more precipitous and aggressively pushing information technology's premises.
fun scaleInfiniteTransition ( initialValue: Float = 0f, targetValue: Float, durationMillis: Int, ) : Float { val infiniteTransition = rememberInfiniteTransition() val scale: Bladder past infiniteTransition.animateFloat( initialValue = initialValue, targetValue = targetValue, animationSpec = infiniteRepeatable( animation = tween( durationMillis = durationMillis, easing = LinearEasing ), repeatMode = RepeatMode.Reverse ) ) render scale } Let's create one more than reusable composable which draws single circle on sheet every time its called.
The function parameters allows u.s. to pass different scale, color and radius ratio for us.
fun DrawCircleOnCanvas ( scale: Float, color: Color, radiusRatio: Float ) { Sheet( modifier = Modifier .fillMaxSize() .graphicsLayer { scaleX = scale scaleY = scale } ) { drawCircle( color = color, center = Offset( ten = size.width / 2, y = size.acme / 2 ), radius = size.minDimension / radiusRatio ) } } At present we need 3 different circle background colour. Merely instead apply just ane color with variable alpha to make animation await smoother and with less resources.
val circleColor = Color(0xFFffb59c) val frontCircle = circleColor.copy(0.75f) val midCircle = circleColor.copy(0.lf) val backCircle = circleColor.copy(0.25f) I have given different names for each variant colors, making easy to place circles drawn on top of each other.
Now invoke the function DrawCircleOnCanvas( ) three times with different animation properties each time.
DrawCircleOnCanvas( scale = scaleInfiniteTransition(targetValue = 2f, durationMillis = 600), colour = backCircle, radiusRatio = fourf ) DrawCircleOnCanvas( calibration = scaleInfiniteTransition(targetValue = 2.fivef, durationMillis = 800), color = midCircle, radiusRatio = 6f ) DrawCircleOnCanvas( scale = scaleInfiniteTransition(targetValue = 3f, durationMillis = grand), colour = frontCircle, radiusRatio = 12f ) Combining all the in a higher place code, this is the concluding code changes.
@Composable fun InfinitelyFlowingCircles () { val circleColor = Color(0xFFffb59c) val frontCircle = circleColor.copy(0.75f) val midCircle = circleColor.copy(0.50f) val backCircle = circleColor.copy(0.25f) DrawCircleOnCanvas() DrawCircleOnCanvas() DrawCircleOnCanvas() } fun DrawCircleOnCanvas ( scale: Bladder, color: Color, radiusRatio: Float ) { Canvas() { drawCircle() } } fun scaleInfiniteTransition ( initialValue: Float = 0f, targetValue: Float, durationMillis: Int, ) : Float { val infiniteTransition = rememberInfiniteTransition() val scale: Float by infiniteTransition.animateFloat() render scale } Concluding changes
Combine search animation and circles in one composable.
Nosotros have earlier completed animative search in composable role AnimateSearch.
At present 3 pulsating circles are in other composable function InfinitelyFlowingCircles.
Bring both in same composable and centre align them to achieve the final land of animation.
@Composable fun AnimatedCirclesAndSearch () { InfinitelyFlowingCircles() Box( modifier = Modifier .fillMaxSize() .padding(bottom = 28.dp, cease = 28.dp), contentAlignment = Alignment.Eye ) { AnimateSearch() } } I accept added extra Box and padding to AnimateSearch( ) so that I tin brand adjustments to center align them.
That's information technology !
Take a expect at GitHub repository which I have linked below has complete code case on building advanced layouts, fetching data from api, animations, draw on canvas, search functionality, loader, UI state handling, Image loading, low-cal/dark theme with MD3, palette usage etc.
Read all the detailed guidelines from Android documentation, information technology covers everything in much depth.
5. Projection lawmaking and Resources
Android Documentation on Architecture.
1. Animations with jetpack etch
two. Codelab on compose animations
3. Core compose animations android
Become Author
We are making content on new declarative UI kit Jetpack Etch, if you are willing to build content join us and we will help you become started.
Here We Go Again : (
if (article == helpful) { println("Similar and subscribe to weblog newsletter.") } else { println("Let me know what i should blog on.") } Source: https://developersbreach.com/custom-shape-animations-pulsating-circles-canvas-compose/
Belum ada Komentar untuk "Draw Animated Circle in Android"
Posting Komentar