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

Best practices for animations in Android

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.
Avatar for GDG SPb GDG SPb
September 30, 2017

Best practices for animations in Android

Как найти идеальный баланс между фантазией дизайнеров и симпатией пользователей при создании анимации в Android? Как выбрать правильный инструмент и когда стоит его использовать, а когда — нет? Понятно и интересно в докладе “Рецепты анимаций в Android”

Avatar for GDG SPb

GDG SPb

September 30, 2017
Tweet

More Decks by GDG SPb

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