Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Best practices for animations in Android

Artur Vasilov
September 30, 2017

Best practices for animations in Android

В Android существует большое количество средств для создания различных анимаций: начиная от классов Animation и ObjectAnimator и заканчивая новомодными CircularReveal и Spring Animation. Однако в действительности разработчики сталкиваются с большим числом проблем при реализации фантазий дизайнеров или же реализуют излшне сложные анимации, которые отпугивают пользователей. Как бороться с этими проблемами, когда что стоит использовать и, самое главное, когда ничего использовать не нужно - я расскажу в рамках доклада.

Видео https://www.youtube.com/watch?v=_Gdu2j4xVyc&list=PL-E8ovIUgWKKnlniOFQDlHo1jdTmGcWPe&index=3

Artur Vasilov

September 30, 2017
Tweet

More Decks by Artur Vasilov

Other Decks in Programming

Transcript

  1. Why? › There are almost no talks about animations in

    Android › It’s complicated › It’s necessary › And here I’m https://material.io/guidelines/motion/material-motion.html 2
  2. 4

  3. 5

  4. 6

  5. 7

  6. 8

  7. 9

  8. Animations in Android › Animation › Animator › LayoutTransition ›

    Ripple › Shared Element Transition › Circular Reveal › Spring Animation, Lottie, Animated Vector, Canvas, Open GL, … 12
  9. Animation › Bugs › Only changes the visual representation of

    an object › Only supports View animations › Don’t use it 15
  10. Animator ValueAnimator animator = ValueAnimator.ofFloat(1f, 2f); animator.setDuration(300); animator.setInterpolator(new BounceInterpolator()); animator.addUpdateListener(valueAnimator

    -> { float value = (float) valueAnimator.getAnimatedValue(); button.setScaleX(value); button.setScaleY(value); }); animator.start();
  11. Animator ValueAnimator animator = ValueAnimator.ofFloat(1f, 2f); animator.setDuration(500); animator.setInterpolator(new BounceInterpolator()); animator.addUpdateListener(valueAnimator

    -> { float value = (float) valueAnimator.getAnimatedValue(); button.setScaleX(value); button.setScaleY(value); }); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { // TODO : do something on animation end } }); animator.start();
  12. Interpolator public interface TimeInterpolator { /** * Maps a value

    representing the elapsed fraction of an animation to a value that * represents the interpolated fraction. This interpolated value is then multiplied * by the change in value of an animation to derive the animated value at the current * elapsed animation time. */ float getInterpolation(float input); }
  13. 21

  14. Evaluator public interface TypeEvaluator<T> { /** * This function returns

    the result of linearly interpolating the start and end * values, with fraction representing the proportion between the start and end * values. The calculation is a simple parametric calculation: * result = x0 + t * (x1 - x0), where x0 is startValue, x1 is endValue, * and t is fraction. */ public T evaluate(float fraction, T startValue, T endValue); }
  15. First way ValueAnimator.ofArgb (API 21+) ValueAnimator animator = ValueAnimator.ofArgb(colorFrom, colorTo);

    animator.setDuration(duration); animator.setStartDelay(startDelay); animator.addUpdateListener(animation -> { target.setBackgroundColor((int) animation.getAnimatedValue()); }); animator.start(); С н цвет не ав л н
  16. HSV final float[] from = new float[3]; final float[] to

    = new float[3]; Color.colorToHSV(colorFrom, from); Color.colorToHSV(colorTo, to); ValueAnimator animator = ValueAnimator.ofFloat(0, 1); final float[] hsv = new float[3]; animator.addUpdateListener(animation -> { // Transition along each axis of HSV (hue, saturation, value) hsv[0] = from[0] + (to[0] - from[0]) * animation.getAnimatedFraction(); hsv[1] = from[1] + (to[1] - from[1]) * animation.getAnimatedFraction(); hsv[2] = from[2] + (to[2] - from[2]) * animation.getAnimatedFraction(); target.setBackgroundColor(Color.HSVToColor(hsv)); }); animator.start();
  17. ViewPropertyAnimator vs Animator ViewPropertyAnimator › Uses Animator under the hood

    › For views only (for many properties) › Easy and flexible API Animator › More methods to control 28
  18. Animator vs Animation Use Animator since Animation: › Bugs ›

    Only changes the visual representation of an object › Only supports View animations 29
  19. Transition › Powerful › Very flexible API TransitionManager.beginDelayedTransition( container, new

    Transition() // some custom transition ); // change property of some view in the container С н цвет не ав л н
  20. More about transitions Backport › https://github.com/andkulikov/Transitions-Everywhere › Support library Articles

    › https://medium.com/@andkulikov/animate-all-the-things- transitions-in-android-914af5477d50 › https://medium.com/@andkulikov/support-library-for-transitions- overview-and-comparison-c41be713cf8c 35
  21. Shared Element Transition › Strongly related with Transition API ›

    Activity & Fragment › API 21+ (no backport) 40
  22. 44

  23. SpringForce SpringAnimation springAnimation = new SpringAnimation( button, DynamicAnimation.TRANSLATION_Y, 500 );

    SpringForce springForce = springAnimation.getSpring(); springForce.setDampingRatio(0.5f); springForce.setStiffness(1000f); springAnimation.start();
  24. Lottie › Adobe after effects › Only with Android API

    (no native libraries) › Extremely simple › May be used for onboarding or splash › Complex animations are slow › Has almost all support libraries in dependency list (19k+ methods) 54
  25. RecyclerView.ItemAnimator @Override protected void animateRemoveHolder(@NonNull RecyclerView.ViewHolder holder) { int duration

    = getResources().getInteger(R.integer.medium_animation_duration); ViewCompat.animate(holder.itemView) .translationX(holder.itemView.getRootView().getWidth()) .setDuration(duration) .setListener(new BaseItemAnimator.DefaultRemoveVpaListener(holder)) .setStartDelay(getRemoveDelay(holder)) .start(); }
  26. Animation callbacks public final boolean isRunning(ItemAnimatorFinishedListener listener) { boolean running

    = isRunning(); if (listener != null) { if (!running) { listener.onAnimationsFinished(); } else { mFinishedListeners.add(listener); } } return running; } public final void dispatchAnimationsFinished() { final int count = mFinishedListeners.size(); for (int i = 0; i < count; ++i) { mFinishedListeners.get(i).onAnimationsFinished(); } mFinishedListeners.clear(); }
  27. Animation callbacks › Changing items in RecyclerView may be performed

    without animation › Use LayoutManager to understand if change operation will be animated 60
  28. And the last things › Are you inflating operations fast

    enough? › Increase animation duration during developing and debugging › Think about finishing animation in onPause method › Use animations! › Don’t use animations! 61