Material Animations: show me the code! (Codemotion 2015)

Material Animations: show me the code! (Codemotion 2015)

** Codemotion Madrid 2015 **

- Why animate?
- Good animation samples
- Available tools to animate
- Transition Framework
- Activity transitions
- Shared element transitions
- View property animations
- Complex animations
- Circular Reveal

> Resources

Material Animations: Code Samples

https://github.com/lgvalle/Material-Animations

Alex Lockwood: Transition Framework
http://goo.gl/y4ZSsp

Saul Molinero: User interface
http://goo.gl/8gex9n

Chris Basha: Overhauling the Twitter Experience on Android

https://goo.gl/F281b2

Material Witness: How Android material applications work

https://youtu.be/97SWYiRtF0Y

Pasquale D’Silva: Designing with animation

https://youtu.be/TMe0WnkF1Lc

8897931773317248080248df1250a8ea?s=128

Luis G. Valle

November 27, 2015
Tweet

Transcript

  1. Material Animations Show me the code! @lgvalle lgvalle.xyz

  2. Why animate?

  3. The Elevator Tale how to avoid user frustration

  4. Why animate? London

  5. Why animate? Nova

  6. Why animate? The elevator

  7. Why animate? Frustration

  8. Animations teach what is happening · what can i do

  9. Where things go? What can I do? Where am I?

    Where things come from?
  10. https://medium.com/@BashaChris/overhauling-the-twitter-experience-on-android-80f5b09e7c67 Overhauling the Twitter Experience on Android Where things come

    Where things go? Where am I? What can I do?
  11. Where things come Where things go? Where am I? What

    can I do?
  12. Where things come Where things go? Where am I? What

    can I do?
  13. Where things come Where things go? Where am I? What

    can I do?
  14. Where things come Where things go? Where am I? What

    can I do?
  15. What can be animated? Layout content Shared elements View Properties

    x
  16. Property Animation System
 (API 12) View property changes Transition Framework


    (API 19) View property changes Layout changes ViewAnimationUtils
 (API 21) CircularReveal Activity Transitions Fragment Transitions How can we animate?
  17. Property Animation System (API 12) View property changes Transition Framework


    (API 19) View property changes Layout changes ViewAnimationUtils (API 21) CircularReveal Activity Transitions Fragment Transitions How can we animate?
  18. Animate screen transitions exit · enter · shared startActivity(B) A

    Exit Enter A B B … B Return Reenter B A A … back()
  19. startActivity(B) A Exit Transition Enter
 Transition A B B B

    Return
 Transition Reenter
 Transition B A A back()
  20. startActivity(B) A Exit Transition Enter
 Transition A B B B

    Return
 Transition Reenter
 Transition B A A Default: 
 Cross-fade back() Default: 
 Reversed enter/exit
  21. startActivity(B) A Exit Transition Enter
 Transition A B B B

    Return
 Transition Reenter
 Transition B A A Default: 
 Cross-fade back() Default: 
 Reversed enter/exit But you can customise!
  22. Explode Slide Fade Activity transition custom effects

  23. startActivity(B) A Exit Transition Enter
 Transition A B B B

    Return
 Transition Reenter
 Transition B A A back()
  24. startActivity(B) A Exit Transition Enter
 Transition A B B B

    Return
 Transition Reenter
 Transition B A A back()
  25. > activities/Activity_A.java @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);

    
 Explode explode = new Explode(); getWindow().setExitTransition(explode); }
 Exit Transition @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_details);
 }
 > activities/Activity_B.java
  26. > activities/Activity_A.java @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);

    
 Explode explode = new Explode(); getWindow().setExitTransition(explode); }
 Exit Transition @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_details);
 }
 > activities/Activity_B.java
  27. startActivity(B) A Exit Transition Enter
 Transition A B B B

    Return
 Transition Reenter
 Transition B A A back()
  28. startActivity(B) A Exit Transition Enter
 Transition A B B B

    Return
 Transition Reenter
 Transition B A A back() Default:
 Transitions 
 Overlap
  29. > activities/Activity_A.java @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);

    
 Explode explode = new Explode(); getWindow().setExitTransition(explode); }
 Disable Overlap @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_details);
 }
 > activities/Activity_B.java
  30. > activities/Activity_A.java @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);

    
 Explode explode = new Explode(); getWindow().setExitTransition(explode); }
 Disable Overlap @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_details); getWindow().setAllowEnterTransitionOverlap(false);
 }
 > activities/Activity_B.java
  31. > activities/Activity_A.java @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);

    
 Explode explode = new Explode(); getWindow().setExitTransition(explode); }
 Disable Overlap @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_details); getWindow().setAllowEnterTransitionOverlap(false);
 }
 > activities/Activity_B.java
  32. > activities/Activity_A.java @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);

    
 Explode explode = new Explode();
 explode.excludeTarget(R.id.toolbar, true); getWindow().setExitTransition(explode); }
 Exclude Views @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_details);
 getWindow().setAllowEnterTransitionOverlap(false);
 }
 > activities/Activity_B.java
  33. > activities/Activity_A.java @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);

    
 Explode explode = new Explode();
 explode.excludeTarget(R.id.toolbar, true); getWindow().setExitTransition(explode); }
 Exclude Views @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_details);
 getWindow().setAllowEnterTransitionOverlap(false);
 }
 > activities/Activity_B.java
  34. startActivity(B) A Exit Transition Enter
 Transition A B B B

    Return
 Transition Reenter
 Transition B A A back()
  35. startActivity(B) A Exit Transition Enter
 Transition A B B B

    Return
 Transition Reenter
 Transition B A A back()
  36. > activities/Activity_A.java @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);

    
 Explode explode = new Explode();
 explode.excludeTarget(R.id.toolbar, true); getWindow().setExitTransition(explode); }
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_details);
 getWindow().setAllowEnterTransitionOverlap(false);
 }
 > activities/Activity_B.java Return Transition
  37. > activities/Activity_A.java @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);

    
 Explode explode = new Explode();
 explode.excludeTarget(R.id.toolbar, true); getWindow().setExitTransition(explode); }
 Return Transition @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_details);
 getWindow().setAllowEnterTransitionOverlap(false);
 
 Slide slide = new Slide(Gravity.RIGHT);
 getWindow().setReturnTransition(slide);
 }
 > activities/Activity_B.java
  38. startActivity(B) A Exit Transition Enter
 Transition A B B B

    Return
 Transition Reenter
 Transition B A A back() Shared Element 
 has its own transitions Reversed shared element transition
  39. res/values/styles.xml <style name=“MaterialAnimations.Main"> <item name=“android:windowContentTransitions”>true</ item> … </style> 1. Enable

    content transition activities/Activity_A.java @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState); getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
 … }
 -OR-
  40. <CardView 
 android:id=“@+id/rowView”
 android:transitionName=“rowName”
 />
 <LinearLayout android:id=“@+id/detailView”
 android:transitionName=“rowName”
 />
 2.

    Common Transition Name
  41. <CardView 
 android:id=“@+id/rowView”
 android:transitionName=“rowName”
 />
 <LinearLayout android:id=“@+id/detailView”
 android:transitionName=“rowName”
 />
 2.

    Common Transition Name
  42. > activities/Activity_A.java Intent i = new Intent(this, Activity_B.class);
 
 ActivityOptions

    options = ActivityOptions .makeSceneTransitionAnimation( this, rowView, // shared element view "rowName"); // common transition name 
 startActivity(i, options.toBundle());
 3. Start Activity (with options)
  43. startActivity(B) A Exit Transition Enter
 Transition A B B B

    Return
 Transition Reenter
 Transition B A A back() Transition Listener Transition Listener
  44. Transition Listener > activities/Activity_B.java 
 @Override
 protected void onCreate(Bundle savedInstanceState)

    {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_details);
 getWindow().setAllowEnterTransitionOverlap(false);
 
 }

  45. Transition Listener > activities/Activity_B.java 
 @Override
 protected void onCreate(Bundle savedInstanceState)

    {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_details);
 getWindow().setAllowEnterTransitionOverlap(false);
 
 getWindow().getEnterTransition() .addListener(new TransitionListener() {
 @Override
 public void onTransitionEnd(Transition t) {
 fab.setVisibility(View.VISIBLE); fade.removeListener(this);
 } …
 });
 }
 Don’t forget!
  46. Transition Listener > activities/Activity_B.java 
 @Override
 protected void onCreate(Bundle savedInstanceState)

    {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_details);
 getWindow().setAllowEnterTransitionOverlap(false);
 
 getWindow().getEnterTransition() .addListener(new TransitionListener() {
 @Override
 public void onTransitionEnd(Transition t) {
 fab.setVisibility(View.VISIBLE); fade.removeListener(this);
 } …
 });
 }
 @Override
 public void onBackPressed() {
 fab.setVisibility(View.INVISIBLE);
 finishAfterTransition(); }
  47. Animate screen elements property changes · circular reveal

  48. fabView .animate() .alpha(1); (API 12+) Property animation system

  49. fabView .animate() .alpha(1) .scaleX(1f) .scaleY(1f); (API 12+) Property animation system

  50. fabView .animate() .alpha(1) .scaleX(1f) .scaleY(1f) .setDuration(500)
 .setStartDelay(300)
 .setInterpolator(…)
 .setListener(…); (API

    12+) Property animation system
  51. > activities/Activity_B.java Transition fade = getWindow().getEnterTransition();
 fade.addListener(new TransitionListener() {
 public

    void onTransitionEnd(Transition t) {
 fab.setVisibility(View.VISIBLE); fade.removeListener(this); }
 }); public void onBackPressed() {
 fab.setVisibility(View.INVISIBLE);
 finishAfterTransition(); } (API 12+) Property animation system
  52. > activities/Activity_B.java Transition fade = getWindow().getEnterTransition();
 fade.addListener(new TransitionListener() {
 public

    void onTransitionEnd(Transition t) {
 fab.animate() .scaleX(1f) .scaleY(1f) fade.removeListener(this); }
 }); public void onBackPressed() {
 fab.animate() .scaleX(0f) .scaleY(0f)
 .withEndAction(new Runnable() {
 @Override
 public void run() {
 finishAfterTransition();
 }
 }); } (API 12+) Property animation system
  53. > activities/Activity_B.java Transition fade = getWindow().getEnterTransition();
 fade.addListener(new TransitionListener() {
 public

    void onTransitionEnd(Transition t) {
 fab.animate() .scaleX(1f) .scaleY(1f) fade.removeListener(this); }
 }); public void onBackPressed() {
 fab.animate() .scaleX(0f) .scaleY(0f)
 .withEndAction(new Runnable() {
 @Override
 public void run() {
 finishAfterTransition();
 }
 }); } (API 12+) Property animation system
  54. What about complex animations?

  55. TransitionManager.beginDelayedTransition StartTransition Transition Manager

  56. StartTransition Save Start State TransitionManager.beginDelayedTransition Transition Manager

  57. StartTransition Capture end state Save Start State TransitionManager.beginDelayedTransition Transition Manager

  58. StartTransition Capture end state Animate difference Save Start State TransitionManager.beginDelayedTransition

    Transition Manager
  59. public void onClickFab() { Transition transition = TransitionInflater.from(this) .inflateTransition(R.transition.changebounds_with_arcmotion); TransitionManager

    .beginDelayedTransition(viewRoot, transition);
 fab.setLayoutParams( new RelativeLayout.LayoutParams( WRAP_CONTENT, WRAP_CONTENT, CENTER_HORIZONTAL, ALIGN_PARENT_BOTTOM) ); } Fab Transition
  60. public void onClickFab() { Transition transition = TransitionInflater.from(this) .inflateTransition(R.transition.changebounds_with_arcmotion); TransitionManager

    .beginDelayedTransition(viewRoot, transition);
 fab.setLayoutParams( new RelativeLayout.LayoutParams( WRAP_CONTENT, WRAP_CONTENT, CENTER_HORIZONTAL, ALIGN_PARENT_BOTTOM) ); } Fab Transition Inflate transition from XML!
  61. activities/TargetActivity.java <?xml version="1.0" encoding="utf-8"?>
 <changeBounds 
 android:duration="@integer/anim_duration_long"
 android:interpolator=“@android/decelerate_cubic">
 <arcMotion
 android:maximumAngle="45"


    android:minimumHorizontalAngle="90"
 android:minimumVerticalAngle="0" />
 
 </changeBounds> > res/transitions/changebounds_with_arcmotion.xml
  62. public void onClickFab() { Transition transition = TransitionInflater.from(this) .inflateTransition(R.transition.changebounds_with_arcmotion); TransitionManager

    .beginDelayedTransition(viewRoot, transition);
 fab.setLayoutParams( new RelativeLayout.LayoutParams( WRAP_CONTENT, WRAP_CONTENT, CENTER_HORIZONTAL, ALIGN_PARENT_BOTTOM) ); } Fab Transition
  63. public void onClickFab() { Transition transition = TransitionInflater.from(this) .inflateTransition(R.transition.changebounds_with_arcmotion); TransitionManager

    .beginDelayedTransition(viewRoot, transition);
 fab.setLayoutParams( new RelativeLayout.LayoutParams( WRAP_CONTENT, WRAP_CONTENT, CENTER_HORIZONTAL, ALIGN_PARENT_BOTTOM) ); } Fab Transition
  64. public void onClickFab() { Transition transition = TransitionInflater.from(this) .inflateTransition(R.transition.changebounds_with_arcmotion); TransitionManager

    .beginDelayedTransition(viewRoot, transition);
 fab.setLayoutParams( new RelativeLayout.LayoutParams( WRAP_CONTENT, WRAP_CONTENT, CENTER_HORIZONTAL, ALIGN_PARENT_BOTTOM) ); } Fab Transition Where is the Circular Reveal?!
  65. Title A Title A Title A Title B Bacon ipsum

    dolor amet sausage bacon pork chop strip steak cow porchetta landjaeger ham sirloin swine leberkas prosciutto turducken ball tip. Pork chop kielbasa shank cow, pig corned beef hamburger Circular Reveal Animation
  66. ViewAnimationUtils .createCircularReveal( view, x, y, initialRadius, finalRadius); Circular Reveal Animation

  67. ViewAnimationUtils .createCircularReveal( viewGroup, x, y, initialRadius, finalRadius); Circular Reveal Animation

  68. ViewAnimationUtils .createCircularReveal( view, x, y, 0f, Math.hypot(…)); Circular Reveal Animation

  69. Circular Reveal Animation int x = (view.getLeft() + view.getRight()) /

    2;
 int y = (view.getTop() + view.getBottom()) / 2;
 int startRadius = 0; int endRadius = Math.hypot(x, y); 
 Animator anim = ViewAnimationUtils .createCircularReveal( view, 
 x, y, startRadius, endRadius); view.setVisibility(View.VISIBLE); anim.start(); (x,y) left right top bottom hypot
  70. (…) transition.addListener(new Transition.TransitionListener() {
 @Override
 public void onTransitionEnd(Transition transition) {


    fab.setVisibility(View.GONE);
 createRevealForView(extraContent);
 }
 }); private Animator createRevealForView(ViewGroup view) { int x = (viewRoot.getLeft() + viewRoot.getRight()) / 2;
 int y = viewRoot.getBottom() - fab.getHeight();
 float finalRadius = (float) Math.hypot(x, y);
 
 Animator anim = ViewAnimationUtils .createCircularReveal(viewRoot, x, y, fab.getWidth(), finalRadius); viewRoot.setVisibility(View.VISIBLE);
 anim.start();
 } Circular Reveal Animation
  71. - Shared element Transition - Transition Listener - Enter /

    Exit Transition - Property Animation System - Transition Manager - Circular Reveal
  72. Pasquale D’Silva: Designing with animation
 https://youtu.be/TMe0WnkF1Lc Material Animations: Code Samples


    https://github.com/lgvalle/Material-Animations Alex Lockwood: Transition Framework
 http://goo.gl/y4ZSsp Saul Molinero: User interface 
 http://goo.gl/8gex9n Material Witness: How Android material applications work
 https://youtu.be/97SWYiRtF0Y Chris Basha: Overhauling the Twitter Experience on Android
 https://goo.gl/F281b2 Resources
  73. Why animate? Happiness!

  74. Questions? Show me the code @lgvalle lgvalle.xyz