aster.cloud aster.cloud
  • /
  • Platforms
    • Public Cloud
    • On-Premise
    • Hybrid Cloud
    • Data
  • Architecture
    • Design
    • Solutions
    • Enterprise
  • Engineering
    • Automation
    • Software Engineering
    • Project Management
    • DevOps
  • Programming
    • Learning
  • Tools
  • About
  • /
  • Platforms
    • Public Cloud
    • On-Premise
    • Hybrid Cloud
    • Data
  • Architecture
    • Design
    • Solutions
    • Enterprise
  • Engineering
    • Automation
    • Software Engineering
    • Project Management
    • DevOps
  • Programming
    • Learning
  • Tools
  • About
aster.cloud aster.cloud
  • /
  • Platforms
    • Public Cloud
    • On-Premise
    • Hybrid Cloud
    • Data
  • Architecture
    • Design
    • Solutions
    • Enterprise
  • Engineering
    • Automation
    • Software Engineering
    • Project Management
    • DevOps
  • Programming
    • Learning
  • Tools
  • About
  • Tech

Custom Canvas Animations In Jetpack Compose ✨

  • aster.cloud
  • May 18, 2022
  • 4 minute read

Using Animatable to achieve Custom Canvas Animations

Imagine the smoothest app experience you’ve seen… Everything moving along with silky smooth transitions and sensible reactions to your interactions…. Are you drooling yet? 🤤 Well you no longer need to dream, as adding animations with Compose will make this dream a reality. Don’t believe me? Read on.

Compose has a range of Animation APIs that cover many different use cases. The simplest animation API is <a class="au lx" href="https://developer.android.com/reference/kotlin/androidx/compose/animation/package-summary#AnimatedVisibility(kotlin.Boolean,androidx.compose.ui.Modifier,androidx.compose.animation.EnterTransition,androidx.compose.animation.ExitTransition,kotlin.String,kotlin.Function1)" target="_blank" rel="noopener ugc nofollow">AnimatedVisibility</a>. We can use it to animate the visibility of any Composable by wrapping it in an AnimatedVisibility Composable and providing a boolean that toggles the visibility:


Partner with aster.cloud
for your next big idea.
Let us know here.



From our partners:

CITI.IO :: Business. Institutions. Society. Global Political Economy.
CYBERPOGO.COM :: For the Arts, Sciences, and Technology.
DADAHACKS.COM :: Parenting For The Rest Of Us.
ZEDISTA.COM :: Entertainment. Sports. Culture. Escape.
TAKUMAKU.COM :: For The Hearth And Home.
ASTER.CLOUD :: From The Cloud And Beyond.
LIWAIWAI.COM :: Intelligence, Inside and Outside.
GLOBALCLOUDPLATFORMS.COM :: For The World's Computing Needs.
FIREGULAMAN.COM :: For The Fire In The Belly Of The Coder.
ASTERCASTER.COM :: Supra Astra. Beyond The Stars.
BARTDAY.COM :: Prosperity For Everyone.

/* Copyright 2022 Google LLC.	
   SPDX-License-Identifier: Apache-2.0 */

var showText by remember {
    mutableStateOf(true)
}
AnimatedVisibility(visible = showText) {
    RoundedRect()
}
AnimatedVisibility in action

This is a quick way to get fluid user interactions in your Compose apps. But what if we wanted to do something more complex, like animating the rotation or color of our custom drawing?

Custom drawing animating rotation and color change over time

The Animation documentation covers the different APIs that will enable you to achieve these sorts of animations and we are going to dive into one of those options: Animatable.

But before we jump into how to achieve this with Compose, let’s remind ourselves how to achieve custom animations in the standard view system:

Reminiscing on the Standard View approach 😶‍🌫️

Without Compose, you’d need to use something like ValueAnimator or ObjectAnimator to animate properties of your custom view. I covered this example in a previous talk.

Below is a sample of how to animate two properties of a custom view that draws a rounded rect, namely a rotation angle and a color Int. We use the ValueAnimator.ofPropertyValuesHolder to animate multiple properties at the same time, calling invalidate() on the view. This triggers a redraw and consequently, the animation runs as the properties are updated.

Read More  Android Dev Summit 2019 | Permissions On Android
/* Copyright 2022 Google LLC.	
   SPDX-License-Identifier: Apache-2.0 */
class CustomCanvasAnimationView @JvmOverloads constructor(
   context: Context,
   attrs: AttributeSet? = null,
   defStyle: Int = 0) : View(context, attrs, defStyle) {

   private var angle = 0f

   @ColorInt
   private var color: Int = Color.GREEN
       set(value) {
           field = value
           paint.color = value
       }
   private val paint = Paint()
   private val sizeBoxPx = SIZE_BOX.toPx

   fun animateViewChanges(toAngle: Float, @ColorInt toColor: Int) {
       val propAngle = PropertyValuesHolder.ofFloat(PROP_ANGLE, angle, toAngle)
       val propColor = PropertyValuesHolder.ofInt(PROP_COLOR, color, toColor)
       ValueAnimator.ofPropertyValuesHolder(propColor, propAngle).apply      {
           setEvaluator(ArgbEvaluator())
           duration = 3000
           addUpdateListener { animation ->
               [email protected] = animation.getAnimatedValue(PROP_ANGLE) as Float
               [email protected] = animation.getAnimatedValue(PROP_COLOR) as Int
               invalidate() // performs animation as it calls onDraw() again
           }
           start()
       }
   }

   override fun onDraw(canvas: Canvas) {
       // use newly updated angle and color, this onDraw function is called multiple times to
       // produce the animation
       canvas.save()
       canvas.rotate(angle, sizeBoxPx / 2f, sizeBoxPx / 2f)
       canvas.drawRoundRect(0f, 0f, sizeBoxPx, sizeBoxPx, 16f, 16f, paint)
       canvas.restore()
   }

   companion object {
       private const val PROP_ANGLE = "angle"
       private const val PROP_COLOR = "color"
       private const val SIZE_BOX = 200f
   }
}

val Float.toPx get() = this * Resources.getSystem().displayMetrics.density

Using Compose to Animate Custom Drawing 🎨

To implement this animation in Compose, we create two remembered Animatable states–one for the angle, and one for the color. The angle will animate from 0–360° and the color will animate from Color.Green to Color.Blue, we will then use these two values to draw our elements on the Canvas.

/* Copyright 2022 Google LLC.	
   SPDX-License-Identifier: Apache-2.0 */
@Composable
fun CustomCanvasAnimation() {
   val angle = remember {
       Animatable(0f)
   }
   val color = remember {
       Animatable(green, typeConverter = Color.VectorConverter(ColorSpaces.LinearSrgb))
   }

   LaunchedEffect(angle, color) {
       launch {
           angle.animateTo(360f, animationSpec = tween(3000))
       }
       launch {
           color.animateTo(blue, animationSpec = tween(3000))
       }
   }
   Canvas(modifier = Modifier.size(200.dp),
       onDraw = {
           rotate(angle.value) {
               drawRoundRect(
                   color = color.value,
                   cornerRadius = CornerRadius(16.dp.toPx())
               )
           }
       }
   )
}

All the animation logic is in the same Composable as the drawing logic. Leveraging the same classes and functions that are used in Composables — such as coroutines and Compose’s State class to store the animation progress.

Read More  21 New Ways Google Cloud Is Improving Observability With Cloud Ops

You’ll notice the color animatable looks a bit different: We’ve defined a <a class="au lx" href="https://developer.android.com/reference/kotlin/androidx/compose/animation/core/TwoWayConverter" target="_blank" rel="noopener ugc nofollow">TwoWayConverter</a> to convert the color into an AnimationVector. The Color.VectorConverter transforms between a Color and a 4 part AnimationVector storing the red, green, blue and alpha components of the color. In the previous view sample, we needed to add the ArgbEvaluator to achieve the same effect.

To start the animations as soon as the Composable is added to the Composition, we use the <a class="au lx" href="https://developer.android.com/jetpack/compose/side-effects#launchedeffect" target="_blank" rel="noopener ugc nofollow">LaunchedEffect</a> class. This will only run again when the provided keys change. We then use the animateTo function on the previously defined Animatable, this is a suspend function that needs to be called from a coroutine context.

In order to run the animations in parallel, we call launch twice, calling each animateTo in a new coroutine. If we wanted to run the animations sequentially, we would change the above LaunchedEffect block to use the same coroutine:

/* Copyright 2022 Google LLC.	
   SPDX-License-Identifier: Apache-2.0 */
LaunchedEffect(angle, color) {
   launch {
       angle.animateTo(360f, animationSpec = tween(3000))
       color.animateTo(blue, animationSpec = tween(3000))
   }
}

Running the animations in the same coroutine will suspend the thread until angle.animateTo() has completed running, then color.animateTo() will run. For more detail around using coroutines for animations — check out this video.

The last thing that remains is to use these two properties to draw something! ✏️ The Canvas onDraw function uses the animatable values — angle.value and color.value to rotate and set the color of the rounded rectangle. Compose automatically redraws when these values change. We don’t need to call invalidate.

That’s it! Using Animatable, we can achieve custom animations in the same way as we were previously using ValueAnimator. We’ve achieved a more readable version and less lines of code using the Compose version than the ValueAnimator approach.

Read More  Google Play Coffee Break With Creatrip | Setting Up Your Business For Global Reach

And if less code hasn’t convinced you yet… Using <a class="au lx" href="https://developer.android.com/reference/kotlin/androidx/compose/animation/core/KeyframesSpec" target="_blank" rel="noopener ugc nofollow">keyframes</a> might be the real drawcard. Keyframes in Compose give you the ability to change key sections (frames) of your animations at certain time intervals.

For example, if we want to set specific colors to animate at certain points of our animation, we can do the following:

/* Copyright 2022 Google LLC.	
   SPDX-License-Identifier: Apache-2.0 */
LaunchedEffect(angle, color) {
        launch {
            angle.animateTo(360f, animationSpec = tween(3000))
        }
        launch {
            color.animateTo(Color.Black, animationSpec = keyframes {
                    durationMillis = 3000
                    Color.Red at 500 with LinearEasing
                    Color.Yellow at 1000 with FastOutSlowInEasing
                    Color.Green at 1500 with FastOutLinearInEasing
                    Color.Blue at 2000 with FastOutLinearInEasing
                    Color.Magenta at 2500 with FastOutLinearInEasing
                }
            ) {
                // callback with animation values if you need them
            }
        }
 }

The above example creates a keyframes AnimationSpec object, and provides it with the different Colors that should be animated to at specific time intervals with a specified Easing Curve.

It is worth noting that Animatable is a low level animation API offered by Compose, many of the higher level convenience APIs are based on top of Animatable. For example, animateColorAsState() wraps the above logic for Color conversions using TwoWayConverter under the hood. animateFloatAsState() could also be used for animating the angle. The animate*AsState APIs allow you to animate independently based on a state change, whereas Animatable offers more flexibility and control of your animation: allowing coordinating animations, indeterminate animations triggered by gestures etc.

For a more real world example, have a look at the custom date selection pill animation in the Crane sample.

For more information on different kinds of Animation in Compose, check out the Animation docs, the Animation codelab, or the Motion Compose sample on Github for more examples.

Share your drool-worthy animations with me on Twitter @riggaroo.

Bye for now! 👋

By Rebecca Franks
Source Android


For enquiries, product placements, sponsorships, and collaborations, connect with us at [email protected]. We'd love to hear from you!

Our humans need coffee too! Your support is highly appreciated, thank you!

aster.cloud

Related Topics
  • Android
  • AnimatedVisibility
  • Animations
  • google
  • Jetpack Compose
You May Also Like
Getting things done makes her feel amazing
View Post
  • Computing
  • Data
  • Featured
  • Learning
  • Tech
  • Technology

Nurturing Minds in the Digital Revolution

  • April 25, 2025
View Post
  • Tech

Deep dive into AI with Google Cloud’s global generative AI roadshow

  • February 18, 2025
Volvo Group: Confidently ahead at CES
View Post
  • Tech

Volvo Group: Confidently ahead at CES

  • January 8, 2025
zedreviews-ces-2025-social-meta
View Post
  • Featured
  • Gears
  • Tech
  • Technology

What Not to Miss at CES 2025

  • January 6, 2025
View Post
  • Tech

IBM and Pasqal Plan to Expand Quantum-Centric Supercomputing Initiative

  • November 21, 2024
Black Friday Gifts
View Post
  • Tech

Black Friday. How to Choose the Best Gifts for Yourself and Others, Plus Our Top Recommendations.

  • November 16, 2024
zedreviews-Apple-iPhone-16-Pro-finish-lineup-240909
View Post
  • Featured
  • Gears
  • Tech
  • Technology
  • Tools

Apple debuts iPhone 16 Pro and iPhone 16 Pro Max

  • September 10, 2024
zedreviews-Apple-iPhone-16-Apple-Intelligence-240909
View Post
  • Featured
  • Gears
  • Tech
  • Technology

Apple introduces iPhone 16 and iPhone 16 Plus

  • September 10, 2024

Stay Connected!
LATEST
  • college-of-cardinals-2025 1
    The Definitive Who’s Who of the 2025 Papal Conclave
    • May 7, 2025
  • conclave-poster-black-smoke 2
    The World Is Revalidating Itself
    • May 6, 2025
  • oracle-ibm 3
    IBM and Oracle Expand Partnership to Advance Agentic AI and Hybrid Cloud
    • May 6, 2025
  • 4
    Conclave: How A New Pope Is Chosen
    • April 25, 2025
  • Getting things done makes her feel amazing 5
    Nurturing Minds in the Digital Revolution
    • April 25, 2025
  • 6
    AI is automating our jobs – but values need to change if we are to be liberated by it
    • April 17, 2025
  • 7
    Canonical Releases Ubuntu 25.04 Plucky Puffin
    • April 17, 2025
  • 8
    United States Army Enterprise Cloud Management Agency Expands its Oracle Defense Cloud Services
    • April 15, 2025
  • 9
    Tokyo Electron and IBM Renew Collaboration for Advanced Semiconductor Technology
    • April 2, 2025
  • 10
    IBM Accelerates Momentum in the as a Service Space with Growing Portfolio of Tools Simplifying Infrastructure Management
    • March 27, 2025
about
Hello World!

We are aster.cloud. We’re created by programmers for programmers.

Our site aims to provide guides, programming tips, reviews, and interesting materials for tech people and those who want to learn in general.

We would like to hear from you.

If you have any feedback, enquiries, or sponsorship request, kindly reach out to us at:

[email protected]
Most Popular
  • 1
    Tariffs, Trump, and Other Things That Start With T – They’re Not The Problem, It’s How We Use Them
    • March 25, 2025
  • 2
    IBM contributes key open-source projects to Linux Foundation to advance AI community participation
    • March 22, 2025
  • 3
    Co-op mode: New partners driving the future of gaming with AI
    • March 22, 2025
  • 4
    Mitsubishi Motors Canada Launches AI-Powered “Intelligent Companion” to Transform the 2025 Outlander Buying Experience
    • March 10, 2025
  • PiPiPi 5
    The Unexpected Pi-Fect Deals This March 14
    • March 13, 2025
  • /
  • Technology
  • Tools
  • About
  • Contact Us

Input your search keywords and press Enter.