Preamble
When too focused on the function of the application, we may underestimate the impact of user experience. Most users will not like applications that are not visually appealing. To make a difference to the application, we need to give the application’s functions a set of Animations
.
Take an example: We need a pizza ordering application in which users can order pizza with a custom amount. How would you introduce this use case now?
Here is an example that you can refer to:
What is needed now is that we need to convert the above GIF image into code for deployment in the application. The job may not sound easy. First we need to take a closer look, maybe even needing to slow down the speed of GIF images to be able to track exactly what is going on. Pay close attention and examine each screen one by one:
- Pizza list screen
- Customizable screen
- Track your delivery screen
We now have a better understanding of design. Now is the time to convert it into code.
Pizza List screen
This screen is showing a list of pizzas and by clicking the CUSTOMIZE
button, the application navigates to a different screen with the pizza image of the current screen and the pizza base of another screen. By adding a few lines of code we can achieve this:
1 2 3 4 5 6 7 8 9 10 |
customiseButton <span class="token punctuation">.</span> setOnClickListener <span class="token punctuation">{</span> val intent <span class="token operator">=</span> <span class="token function">Intent</span> <span class="token punctuation">(</span> this <span class="token punctuation">,</span> CustomiseActivity <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token keyword">class</span> <span class="token punctuation">.</span> java <span class="token punctuation">)</span> val options <span class="token operator">=</span> ActivityOptionsCompat <span class="token punctuation">.</span> <span class="token function">makeSceneTransitionAnimation</span> <span class="token punctuation">(</span> this <span class="token punctuation">,</span> pizzaImageView <span class="token keyword">as</span> View <span class="token punctuation">,</span> <span class="token double-quoted-string string">"pizza"</span> <span class="token punctuation">)</span> <span class="token function">startActivity</span> <span class="token punctuation">(</span> intent <span class="token punctuation">,</span> options <span class="token punctuation">.</span> <span class="token function">toBundle</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> |
Don’t forget to add the following code to your styles.xml
file:
1 2 |
<span class="token operator"><</span> item name <span class="token operator">=</span> <span class="token double-quoted-string string">"android:windowContentTransitions"</span> <span class="token operator">></span> <span class="token boolean">true</span> <span class="token operator"><</span> <span class="token operator">/</span> item <span class="token operator">></span> |
Customization screen
Here we need lots of animations. Before getting started on this screen, let’s learn a bit about ObjectAnimator , ValueAnimator and AnimationSet .
ObjectAnimator
: ThisValueAnimator
ofValueAnimator
provides support forValueAnimator
properties on target objects.ValueAnimator
: This class provides a simple timing tool to run animations, calculate animated values and place them on target objects.AnimationSet
: Represents an Animations group performed together. We need to display multipleanimation
simultaneously or in sequential order.AnimationSet
is best suited for this.
AnimateCheeseHeight
At the beginning of this screen we can see the height of the cheese layer can be increased. So we need to use ValueAnimator
. We need to increase the height from 10dp to 30dp, and we need to update the value with AnimatorUpdateListener
. From there we get the updated height value and update the layout parameters of PizzaCheeseImageView
.
1 2 3 4 5 6 7 8 9 10 |
val anim <span class="token operator">=</span> ValueAnimator <span class="token punctuation">.</span> <span class="token function">ofInt</span> <span class="token punctuation">(</span> pizzaCheeseImageView <span class="token punctuation">.</span> measuredHeight <span class="token punctuation">,</span> height <span class="token punctuation">)</span> anim <span class="token punctuation">.</span> addUpdateListener <span class="token punctuation">{</span> valueAnimator <span class="token operator">-</span> <span class="token operator">></span> val value <span class="token operator">=</span> valueAnimator <span class="token punctuation">.</span> animatedValue <span class="token keyword">as</span> Int val layoutParams <span class="token operator">=</span> pizzaCheeseImageView <span class="token punctuation">.</span> layoutParams layoutParams <span class="token punctuation">.</span> height <span class="token operator">=</span> value pizzaCheeseImageView <span class="token punctuation">.</span> layoutParams <span class="token operator">=</span> layoutParams <span class="token punctuation">}</span> anim <span class="token punctuation">.</span> duration <span class="token operator">=</span> <span class="token number">300</span> anim <span class="token punctuation">.</span> <span class="token function">start</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> |
AnimateCrustHeight
With the height of the cheese layer increasing, we need to increase the height of the crust. We also use ValueAnimator
. In addition, when the height increases, we need to change the radius of the angle to provide a homogeneous shape for the image of the cake base or layer of cheese. So we will update both the height parameters and the corner radius of PizzaCrustImageView
1 2 3 4 5 6 7 8 9 10 11 |
val anim <span class="token operator">=</span> ValueAnimator <span class="token punctuation">.</span> <span class="token function">ofInt</span> <span class="token punctuation">(</span> pizzaCrustImageView <span class="token punctuation">.</span> measuredHeight <span class="token punctuation">,</span> height <span class="token punctuation">)</span> anim <span class="token punctuation">.</span> addUpdateListener <span class="token punctuation">{</span> valueAnimator <span class="token operator">-</span> <span class="token operator">></span> val value <span class="token operator">=</span> valueAnimator <span class="token punctuation">.</span> animatedValue <span class="token keyword">as</span> Int val layoutParams <span class="token operator">=</span> pizzaCrustImageView <span class="token punctuation">.</span> layoutParams layoutParams <span class="token punctuation">.</span> height <span class="token operator">=</span> value pizzaCrustImageView <span class="token punctuation">.</span> layoutParams <span class="token operator">=</span> layoutParams pizzaCrustImageView <span class="token punctuation">.</span> radius <span class="token operator">=</span> value <span class="token punctuation">.</span> <span class="token function">div</span> <span class="token punctuation">(</span> <span class="token number">2</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">toFloat</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> anim <span class="token punctuation">.</span> duration <span class="token operator">=</span> <span class="token number">300</span> anim <span class="token punctuation">.</span> <span class="token function">start</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> |
AnimateToppings
When the user chooses a topping, we need to display an animation that falls from the top of the screen to the top of the pizza cheese. We are using ObjectAnimator
because it has an attribute called translationY
, which helps create overlays to animate from intialY
to destinationY
. In addition, we are using AccelerateInterpolator
help speed up animations
.
1 2 3 4 5 6 |
ObjectAnimator <span class="token punctuation">.</span> <span class="token function">ofFloat</span> <span class="token punctuation">(</span> toppingsLayout <span class="token punctuation">,</span> <span class="token double-quoted-string string">"translationY"</span> <span class="token punctuation">,</span> <span class="token number">0</span> f <span class="token punctuation">,</span> toppingsLayout <span class="token punctuation">.</span> height <span class="token punctuation">.</span> <span class="token function">toFloat</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token number">12</span> f <span class="token punctuation">)</span> <span class="token punctuation">.</span> apply <span class="token punctuation">{</span> interpolator <span class="token operator">=</span> <span class="token function">AccelerateInterpolator</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> duration <span class="token operator">=</span> <span class="token number">600</span> <span class="token function">start</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> |
AnimatePizzaLayout
As we can observe that many animation
are happening, so we can divide them into parts.
FadeCheeseAnimation
1 2 |
val fadeCheese <span class="token operator">=</span> ObjectAnimator <span class="token punctuation">.</span> <span class="token function">ofFloat</span> <span class="token punctuation">(</span> pizzaCheeseImageView <span class="token punctuation">,</span> <span class="token double-quoted-string string">"alpha"</span> <span class="token punctuation">,</span> <span class="token number">1</span> f <span class="token punctuation">,</span> <span class="token number">0</span> f <span class="token punctuation">)</span> |
FadeCrustAnimation
1 2 |
val fadeCrust <span class="token operator">=</span> ObjectAnimator <span class="token punctuation">.</span> <span class="token function">ofFloat</span> <span class="token punctuation">(</span> pizzaCrustImageView <span class="token punctuation">,</span> <span class="token double-quoted-string string">"alpha"</span> <span class="token punctuation">,</span> <span class="token number">1</span> f <span class="token punctuation">,</span> <span class="token number">0</span> f <span class="token punctuation">)</span> |
FadeInPizzaAnimation
1 2 |
val fadeInPizza <span class="token operator">=</span> ObjectAnimator <span class="token punctuation">.</span> <span class="token function">ofFloat</span> <span class="token punctuation">(</span> pizzaImageView <span class="token punctuation">,</span> <span class="token double-quoted-string string">"alpha"</span> <span class="token punctuation">,</span> <span class="token number">0</span> f <span class="token punctuation">,</span> <span class="token number">1</span> f <span class="token punctuation">)</span> |
ScaleUpPizzaXAnimation
1 2 |
val scaleUpPizzaX <span class="token operator">=</span> ObjectAnimator <span class="token punctuation">.</span> <span class="token function">ofFloat</span> <span class="token punctuation">(</span> pizzaImageView <span class="token punctuation">,</span> <span class="token double-quoted-string string">"scaleX"</span> <span class="token punctuation">,</span> <span class="token number">0</span> f <span class="token punctuation">,</span> <span class="token number">0.8</span> f <span class="token punctuation">)</span> |
ScaleUpPizzaYAnimation
1 2 |
val scaleUpPizzaY <span class="token operator">=</span> ObjectAnimator <span class="token punctuation">.</span> <span class="token function">ofFloat</span> <span class="token punctuation">(</span> pizzaImageView <span class="token punctuation">,</span> <span class="token double-quoted-string string">"scaleY"</span> <span class="token punctuation">,</span> <span class="token number">0</span> f <span class="token punctuation">,</span> <span class="token number">14</span> f <span class="token punctuation">)</span> |
TranslatePizzaYAnimation
1 2 |
val translatePizzaY <span class="token operator">=</span> ObjectAnimator <span class="token punctuation">.</span> <span class="token function">ofFloat</span> <span class="token punctuation">(</span> pizzaImageView <span class="token punctuation">,</span> <span class="token double-quoted-string string">"translationY"</span> <span class="token punctuation">,</span> <span class="token number">0</span> f <span class="token punctuation">,</span> <span class="token operator">-</span> <span class="token number">360</span> f <span class="token punctuation">)</span> |
PlayAnimationsTogether
1 2 3 4 |
<span class="token function">AnimatorSet</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> apply <span class="token punctuation">{</span> <span class="token function">play</span> <span class="token punctuation">(</span> fadeCheese <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">with</span> <span class="token punctuation">(</span> fadeCrust <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">with</span> <span class="token punctuation">(</span> fadeInPizza <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">with</span> <span class="token punctuation">(</span> scaleUpPizzaX <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">with</span> <span class="token punctuation">(</span> scaleUpPizzaY <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">with</span> <span class="token punctuation">(</span> translatePizzaY <span class="token punctuation">)</span> <span class="token punctuation">}</span> |
Subscribe to the Delivery screen
In this screen, we need to do an animation
the front of the box and rotate the box with scaling
and translation
.
AnimateFrontCover
We can also use ViewPropertyAnimator instead of ObjectAnimator
for animation
. By using ViewPropertyAnimator
, we can execute multiple animation
together without using AnimatioSet
. It provides a better syntax and an optimized way to animate a view.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
frontCoverImageView <span class="token punctuation">.</span> <span class="token function">animate</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">translationY</span> <span class="token punctuation">(</span> <span class="token number">790</span> f <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">setDuration</span> <span class="token punctuation">(</span> <span class="token number">300</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">setListener</span> <span class="token punctuation">(</span> object <span class="token punctuation">:</span> Animator <span class="token punctuation">.</span> AnimatorListener <span class="token punctuation">{</span> override fun <span class="token function">onAnimationEnd</span> <span class="token punctuation">(</span> animation <span class="token punctuation">:</span> Animator <span class="token operator">?</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> backCoverImageView <span class="token punctuation">.</span> visibility <span class="token operator">=</span> <span class="token constant">VISIBLE</span> backCoverImageView <span class="token punctuation">.</span> alpha <span class="token operator">=</span> <span class="token number">1</span> f pizzaImageView <span class="token punctuation">.</span> visibility <span class="token operator">=</span> <span class="token constant">GONE</span> frontCoverImageView <span class="token punctuation">.</span> visibility <span class="token operator">=</span> <span class="token constant">GONE</span> <span class="token function">rotateBoxAnimation</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> startDelay <span class="token operator">=</span> <span class="token number">500</span> L |
RotateBoxAnimation
Once again we can split the animation
: ScaleDownXAnimation
1 2 |
val scaleDownX <span class="token operator">=</span> ObjectAnimator <span class="token punctuation">.</span> <span class="token function">ofFloat</span> <span class="token punctuation">(</span> backCoverImageView <span class="token punctuation">,</span> <span class="token double-quoted-string string">"scaleX"</span> <span class="token punctuation">,</span> <span class="token number">1</span> f <span class="token punctuation">,</span> <span class="token number">0.6</span> f <span class="token punctuation">)</span> |
ScaleDownYAnimation
1 2 |
val scaleDownY <span class="token operator">=</span> ObjectAnimator <span class="token punctuation">.</span> <span class="token function">ofFloat</span> <span class="token punctuation">(</span> backCoverImageView <span class="token punctuation">,</span> <span class="token double-quoted-string string">"scaleY"</span> <span class="token punctuation">,</span> <span class="token number">1</span> f <span class="token punctuation">,</span> <span class="token number">0.6</span> f <span class="token punctuation">)</span> |
RotateBoxAnimation
1 2 |
val rotateBox <span class="token operator">=</span> ObjectAnimator <span class="token punctuation">.</span> <span class="token function">ofFloat</span> <span class="token punctuation">(</span> backCoverImageView <span class="token punctuation">,</span> <span class="token double-quoted-string string">"rotation"</span> <span class="token punctuation">,</span> <span class="token number">0</span> f <span class="token punctuation">,</span> <span class="token operator">-</span> <span class="token number">45</span> f <span class="token punctuation">)</span> |
TranslateXAnimation
1 2 |
val translateX <span class="token operator">=</span> ObjectAnimator <span class="token punctuation">.</span> <span class="token function">ofFloat</span> <span class="token punctuation">(</span> backCoverImageView <span class="token punctuation">,</span> <span class="token double-quoted-string string">"translationX"</span> <span class="token punctuation">,</span> <span class="token number">0</span> f <span class="token punctuation">,</span> <span class="token number">1000</span> f <span class="token punctuation">)</span> |
PlayAnimationsTogether
1 2 3 4 |
<span class="token function">AnimatorSet</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> apply <span class="token punctuation">{</span> <span class="token function">play</span> <span class="token punctuation">(</span> scaleDownX <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">with</span> <span class="token punctuation">(</span> scaleDownY <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">with</span> <span class="token punctuation">(</span> rotateBox <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">before</span> <span class="token punctuation">(</span> translateX <span class="token punctuation">)</span> <span class="token punctuation">}</span> |
Showtime
Run the code and enjoy the results!