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.

  1. Need a new Animatable property with dissimilar initial float value.
  2. Properties for blitheness remains same except initial float value.
  3. 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.") }

simonstraves1955.blogspot.com

Source: https://developersbreach.com/custom-shape-animations-pulsating-circles-canvas-compose/

Belum ada Komentar untuk "Draw Animated Circle in Android"

Posting Komentar

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel