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

Material Animations - A Deep Dive into Motion D...

Jerrell Mardis
September 16, 2016

Material Animations - A Deep Dive into Motion Design and Animation

A deep dive into the world of animation in Material Design. We'll cover what Material Design is, how natural motion plays a role in its principles and how to create meaningful animations that exhibit the essence of Material Design aims for.

Jerrell Mardis

September 16, 2016
Tweet

More Decks by Jerrell Mardis

Other Decks in Technology

Transcript

  1. MATERIAL ANIMATIONS A Deep Dive into Motion Design and Animation

    twitter.com/jerrellmardis google.com/+jerrellmardis
  2. ABOUT ME • Android Engineer at Salesforce.com • Started out

    as an iOS developer • Have been developing Android apps for 6+ years • GDG Chicago West & Windy City DevCon organizer
  3. –Matías Duarte (VP, Material Design) “A system for designing across

    platforms and screen sizes. With the real utility and usability of surfaces. A system that puts motion at the heart of design.”
  4. MOTION PROVIDES • Context between Views • Hints for gestures

    • Hierarchical and spatial relationships between different elements • Character and polish
  5. WHAT’S AN INTERPOLATOR ? Maps a value representing the elapsed

    fraction of an animation to a value that represents the interpolated fraction.
  6. CUSTOM INTERPOLATOR public class CustomInterpolator implements Interpolator {
 
 @Override


    public float getInterpolation(float v) {
 return (float) Math.pow(v, 4f);
 } }
  7. ACCELERATE DECELERATE INTERPOLATOR public class AccelerateDecelerateInterpolator implements Interpolator {
 


    @Override
 public float getInterpolation(float v) {
 return (float)(Math.cos((v + 1) * PI) / 2.0f) + 0.5f; }
 }
  8. COMMON DURATIONS • 300ms for typical transitions • 375ms for

    large/complex transitions • 225ms for objects entering the screen • 195ms for objects leaving the screen
  9. COMMON DURATIONS • 300ms for typical transitions • 375ms for

    large/complex transitions • 225ms for objects entering the screen LinearOutSlowInInterpolator • 195ms for objects leaving the screen
  10. COMMON DURATIONS • 300ms for typical transitions • 375ms for

    large/complex transitions • 225ms for objects entering the screen LinearOutSlowInInterpolator • 195ms for objects leaving the screen FastOutLinearInInterpolator
  11. SHARED ELEMENT TRANSITIONS • Use their own set of transitions

    states (i.e Enter, Exit, Reenter and Return) • Follows the same order as Window Transitions • Are drawn in the DecorView’s ViewOverlay • Transition API utilizes Scenes to hold view properties to animate between
  12. SHARED ELEMENT TRANSITIONS • All animations are executed in the

    destination Activity • The initial state of the Shared Element is positioned on top of the destination Activity’s View Hierarchy • The Shared Element is animated from its initial state to its final state • Animations are reversed when returning to the previous Activity
  13. 1. Enable activity transitions 2. Add the explode exit transition

    to the initial Activity 3. Share the selected view STEPS TO SUCCESS
  14. 1. Enable activity transitions 2. Add the explode exit transition

    to the initial Activity 3. Share the selected view 4. Add the slide enter tranisition to the destination Activity STEPS TO SUCCESS
  15. STEPS TO SUCCESS 1. Enable activity transitions 2. Add the

    explode exit transition to the initial Activity 3. Share the selected view 4. Add the slide enter tranisition to the destination Activity 5. Add the FAB transform transition
  16. <style name="AppTheme">
 <item name=“android:windowActivityTransitions”>true</item> ...
 </style> <style name="AppTheme" parent=“@android:style/Theme.Material"> ...


    </style> <style name="AppTheme" parent=“@android:style/Theme.AppCompat"> ...
 </style> ENABLE ACTIVITY TRANSITIONS
  17. <!-- ../transition/main_activity_exit.xml -->
 <explode /> <!-- ../values/styles.xml -->
 <style name="AppTheme.Main">


    <item name="android:windowExitTransition">@transition/main_activity_exit</item>
 </style> ADD THE EXIT TRANSITION
  18. <!-- ../transition/main_activity_exit.xml -->
 <explode /> <!-- ../values/styles.xml -->
 <style name="AppTheme.Main">


    <item name="android:windowExitTransition">@transition/main_activity_exit</item>
 </style> <!-- AndroidManifest.xml -->
 <activity android:name=".MainActivity"
 android:theme="@style/AppTheme.Main">
 <intent-filter>
 <action android:name="android.intent.action.MAIN"/>
 <category android:name="android.intent.category.LAUNCHER"/>
 <category android:name="android.intent.category.DEFAULT"/>
 </intent-filter>
 </activity> ADD THE EXIT TRANSITION
  19. // ../MainActivity.java
 List<Pair<View, String>> pairs = new ArrayList<>();
 
 View

    decor = getWindow().getDecorView();
 
 View statusBar = decor.findViewById(android.R.id.statusBarBackground);
 pairs.add(Pair.create(statusBar, statusBar.getTransitionName()));

  20. // ../MainActivity.java
 List<Pair<View, String>> pairs = new ArrayList<>();
 
 View

    decor = getWindow().getDecorView();
 
 View statusBar = decor.findViewById(android.R.id.statusBarBackground);
 pairs.add(Pair.create(statusBar, statusBar.getTransitionName()));
 
 View navBar = decor.findViewById(android.R.id.navigationBarBackground);
 if (navBar != null) {
 pairs.add(Pair.create(navBar, navBar.getTransitionName()));
 }

  21. // ../MainActivity.java
 List<Pair<View, String>> pairs = new ArrayList<>();
 
 View

    decor = getWindow().getDecorView();
 
 View statusBar = decor.findViewById(android.R.id.statusBarBackground);
 pairs.add(Pair.create(statusBar, statusBar.getTransitionName()));
 
 View navBar = decor.findViewById(android.R.id.navigationBarBackground);
 if (navBar != null) {
 pairs.add(Pair.create(navBar, navBar.getTransitionName()));
 }
 
 pairs.add(Pair.create((View) binding.toolbar, binding.toolbar.getTransitionName()));
  22. SHARE THE SELECTED VIEW <!-- ../transition/detail_activity_shared_element.xml --> <transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
 <transitionSet>


    <targets>
 <target android:targetId="@id/item" />
 </targets>
 <changeBounds>
 <arcMotion android:maximumAngle="90"/>
 </changeBounds>
 </transitionSet>
 </transitionSet>
  23. SHARE THE SELECTED VIEW <!-- ../transition/detail_activity_shared_element.xml --> <transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
 <transitionSet>


    <targets>
 <target android:targetId="@id/item" />
 </targets>
 <changeBounds>
 <arcMotion android:maximumAngle="90"/>
 </changeBounds>
 </transitionSet>
 </transitionSet> <!-- ../values/styles.xml -->
 <style name="AppTheme.Details">
 <item name=“android:windowSharedElementEnterTransition"> @transition/detail_activity_shared_element </item>
 </style>
  24. SHARE THE SELECTED VIEW <!-- ../layout/grid_item.xml -->
 <layout xmlns:android="http://schemas.android.com/apk/res/android">
 


    <data>
 <variable name="presenter" type="com.jerrellmardis.materialanimations.PresenterImpl"/>
 <variable name="backgroundColor" type="Integer"/>
 <variable name="id" type="Integer"/>
 </data>
 
 <View
 android:id="@+id/item"
 android:layout_width="match_parent"
 android:layout_height="144dp"
 android:background="@{backgroundColor}"
 android:foreground="?attr/selectableItemBackground"
 android:onClick="@{(view) -> presenter.onItemSelected(view, id, backgroundColor)}"
 android:transitionName="@{@string/shared_element_transition_name + id}"/>
 
 </layout>
  25. SHARE THE SELECTED VIEW // ../MainActivity.java List<Pair<View, String>> pairs =

    buildTransitionPairs(view);
 
 Intent intent = new Intent(this, DetailActivity.class);
 // pass the background color to set on the shared element view in the {@code DetailActivity}
 intent.putExtra(DetailActivity.EXTRA_BG_COLOR, backgroundColor);
 // pass the id (position of the view in the ItemAdapter) of the view to use to build the // unique transitionName in the {@code DetailActivity}
 intent.putExtra(DetailActivity.EXTRA_ID, id);
  26. SHARE THE SELECTED VIEW // ../MainActivity.java List<Pair<View, String>> pairs =

    buildTransitionPairs(view);
 
 Intent intent = new Intent(this, DetailActivity.class);
 // pass the background color to set on the shared element view in the {@code DetailActivity}
 intent.putExtra(DetailActivity.EXTRA_BG_COLOR, backgroundColor);
 // pass the id (position of the view in the ItemAdapter) of the view to use to build the unique transitionName in the {@code DetailActivity}
 intent.putExtra(DetailActivity.EXTRA_ID, id);
 
 ActivityCompat.startActivity(this, intent,
 ActivityOptionsCompat.makeSceneTransitionAnimation(this, pairs.toArray(new Pair[pairs.size()])).toBundle());
  27. SHARE THE SELECTED VIEW // ../DetailActivity.java // bind the id

    and background color to the View
 ActivityDetailBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_detail);
 binding.setId(getIntent().getIntExtra(EXTRA_ID, 0));
 binding.item.setBackgroundColor(getIntent().getIntExtra(EXTRA_BG_COLOR, 0));
  28. SHARE THE SELECTED VIEW // ../DetailActivity.java // bind the id

    and background color to the View
 ActivityDetailBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_detail);
 binding.setId(getIntent().getIntExtra(EXTRA_ID, 0));
 binding.item.setBackgroundColor(getIntent().getIntExtra(EXTRA_BG_COLOR, 0)); <!-- ../layout/activity_detail.xml —> 
 <View android:id="@+id/item"
 android:layout_width="match_parent"
 android:layout_height="200dp"
 android:layout_gravity="top"
 android:transitionName="@{@string/shared_element_transition_name + id}"/>
  29. // ../DetailActivity.java // postpone the transition until the view is

    ready to be drawn
 postponeEnterTransition();
  30. // ../DetailActivity.java // postpone the transition until the view is

    ready to be drawn
 postponeEnterTransition();
 
 final View decor = getWindow().getDecorView();
 decor.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
 @Override
 public boolean onPreDraw() {
 decor.getViewTreeObserver().removeOnPreDrawListener(this);
 startPostponedEnterTransition();
 return true;
 }
 });
  31. <!-- ../transition/detail_activity_enter.xml --> <transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
 <slide android:duration="@android:integer/config_shortAnimTime"
 android:interpolator="@android:interpolator/linear_out_slow_in"
 android:slideEdge="bottom"/>
 <fade/>


    </transitionSet> <!-- ../values/styles.xml -->
 <style name="AppTheme.Details">
 <item name=“android:windowSharedElementEnterTransition"> @transition/detail_activity_shared_element </item>
 <item name="android:windowEnterTransition">@transition/detail_activity_enter</item> </style> ADD THE ENTER TRANSITION
  32. ADD THE FAB TRANSITION <!-- ../transition/fab_transition.xml -->
 <changeBounds xmlns:android="http://schemas.android.com/apk/res/android"
 android:duration="@android:integer/config_mediumAnimTime"


    android:interpolator=“@android:interpolator/accelerate_decelerate"> <arcMotion android:maximumAngle="50"/>
 </changeBounds> // on FAB click, load the fab transition add the FabTransitionCallback
 Transition transition = TransitionInflater.from(view.getContext()).inflateTransition(R.transition.fab_transition);
 transition.addListener(new FabTransitionCallback(fab, revealContainer, revealTextView));
  33. ADD THE FAB TRANSITION <!-- ../transition/fab_transition.xml -->
 <changeBounds xmlns:android="http://schemas.android.com/apk/res/android"
 android:duration="@android:integer/config_mediumAnimTime"


    android:interpolator=“@android:interpolator/accelerate_decelerate"> <arcMotion android:maximumAngle="50"/>
 </changeBounds> // on FAB click, load the fab transition add the FabTransitionCallback
 Transition transition = TransitionInflater.from(view.getContext()).inflateTransition(R.transition.fab_transition);
 transition.addListener(new FabTransitionCallback(fab, revealContainer, revealTextView));
 
 // 1. saves the current property values of all views in the rootView
 // 2. adds an OnPreDrawListener which is triggered on the next layout pass
 TransitionManager.beginDelayedTransition(rootView, transition);
  34. ADD THE FAB TRANSITION <!-- ../transition/fab_transition.xml -->
 <changeBounds xmlns:android="http://schemas.android.com/apk/res/android"
 android:duration="@android:integer/config_mediumAnimTime"


    android:interpolator="@android:interpolator/accelerate_decelerate">
 <arcMotion android:maximumAngle="50"/>
 </changeBounds> // on FAB click, load the fab transition add the FabTransitionCallback
 Transition transition = TransitionInflater.from(view.getContext()).inflateTransition(R.transition.fab_transition);
 transition.addListener(new FabTransitionCallback(fab, revealContainer, revealTextView));
 
 // 1. saves the current property values of all views in the rootView
 // 2. adds an OnPreDrawListener which is triggered on the next layout pass
 TransitionManager.beginDelayedTransition(rootView, transition);
 
 // 3. triggers the OnPreDrawListener created in TransitionManager.beginDelayedTransition
 // 4. OnPreDrawListener retrieves the new property values
 // 5. the system calculates the before/after property values and runs the animations
 fab.setLayoutParams(new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT, CENTER));
  35. ADD THE FAB TRANSITION // ../FabTransitionCallback.java @Override
 public void onTransitionEnd(Transition

    transition) {
 // create and start the circular reveal animation
 Animator anim = ViewAnimationUtils.createCircularReveal(revealContainer, cx, cy, 0, radius);
 anim.setInterpolator(new AccelerateDecelerateInterpolator());
 anim.addListener(new AnimatorListenerAdapter() {
 @Override
 public void onAnimationEnd(Animator animation) {
 // show the text
 revealTextView .animate() .scaleX(1) .scaleY(1) .setInterpolator(new BounceInterpolator()) .setDuration(500) .start();
 }
 });
 anim.start();
 }
  36. ADD THE FAB TRANSITION // ../FabTransitionCallback.java @Override
 public void onTransitionEnd(Transition

    transition) {
 // create and start the circular reveal animation
 Animator anim = ViewAnimationUtils.createCircularReveal(revealContainer, cx, cy, 0, radius);
 anim.setInterpolator(new AccelerateDecelerateInterpolator());
 anim.addListener(new AnimatorListenerAdapter() {
 @Override
 public void onAnimationEnd(Animator animation) {
 // show the text
 revealTextView .animate() .scaleX(1) .scaleY(1) .setInterpolator(new BounceInterpolator()) .setDuration(500) .start();
 }
 });
 anim.start(); 
 // reset the FAB's position and hide it
 fab.setLayoutParams(originalParams);
 fab.setVisibility(View.GONE);
 }
  37. THANK YOU! • Material Design Spec material.google.com • Material Animations

    App Source goo.gl/BSmNyZ • Interpolator Playground App Source goo.gl/YUVIN1 • Nick Butcher’s Plaid App Source goo.gl/d0KIuZ • Animating Views Using Scenes & Transitions goo.gl/gnegWI twitter.com/jerrellmardis google.com/+jerrellmardis