When the Android design support library dropped a few months ago, developers were given all kinds of goodies. Most of these goodies are self-explanatory: The floating action button, you’ve seen that. Snackbars and Tabs? Everyone knows what those are.

But there is also something mysterious lurking in the design support library. Something that has its tentacles throughout. This mysterious thing is known as the CoordinatorLayout .

CoordinatorLayout

You don’t hear much about CoordinatorLayout , probably because when you use it, you generally don’t need to know many of the details. Things just work and they just work well. However, CoordinatorLayout is more powerful than it first seems.

Take a snackbar and a floating action button as an example. Using a CoordinatorLayout , you can ensure that your floating action button will move out of the way when the snack bar pops in.

Just throw a CoordinatorLayout in your layout file:

<android.support.design.widget.CoordinatorLayout android:id= "@+id/container" xmlns:android= "http://schemas.android.com/apk/res/android" xmlns:app= "http://schemas.android.com/apk/res-auto" android:layout_width= "match_parent" android:layout_height= "match_parent" > ... <android.support.design.widget.FloatingActionButton android:id= "@+id/fab" android:layout_width= "wrap_content" android:layout_height= "wrap_content" android:layout_gravity= "bottom|right|end" android:layout_margin= "8dp" android:src= "@drawable/abc_ic_search_api_mtrl_alpha" /> </android.support.design.widget.CoordinatorLayout>

Then show your snack bar:

Snackbar . make ( findViewById ( R . id . container ), "Hey there!" , Snackbar . LENGTH_LONG ). show ();

Magically, your floating action button will move when the snack bar shows up. That’s it!

Out of the box, CoordinatorLayout can also increase the size of your toolbar based on scroll position or hide your toolbar when the user is scrolling down a list. You can customize it with your own behavior, too.

So how does CoordinatorLayout know what to do with the floating action button? How does it know that it should move up the screen when the snack bar comes in?

CoordinatorLayout makes this happen by making use of a CoordinatorLayout.Behavior implemented and declared by FloatingActionButton .

CoordinatorLayout.Behavior

Views within a coordinator layout can specify a Behavior that defines how that view interacts with other views.

@CoordinatorLayout . DefaultBehavior ( FloatingActionButton . Behavior . class ) public class FloatingActionButton extends ImageView { ... }

If you look at the source for FloatingActionButton , you will see its Behavior defined with an annotation on the class declaration.

FloatingActionButton uses FloatingActionButton.Behavior as its default behavior unless you set it to something else. The default knows how to get out of the way of the snackbar when it shows up.

Custom Behavior

So, how do you customize this behavior? You define your own Behavior subclass.

Let’s create a Behavior that shrinks the FloatingActionButton instead of moving it up the screen when the snackbar shows up.

First, in your layout file, use the app:layout_behavior attribute to point to your Behavior subclass:

... <android.support.design.widget.FloatingActionButton android:id= "@+id/fab" android:layout_width= "wrap_content" android:layout_height= "wrap_content" android:layout_gravity= "bottom|right|end" android:layout_margin= "8dp" android:src= "@drawable/abc_ic_search_api_mtrl_alpha" app:layout_behavior= "com.bignerdranch.android.custombehavior.ShrinkBehavior" /> ...

Then, create your class:

public class ShrinkBehavior extends CoordinatorLayout . Behavior < FloatingActionButton > { public ShrinkBehavior ( Context context , AttributeSet attrs ) { super ( context , attrs ); } }

When you define your own behavior, there are many methods that you can override. For this example, there are two that are necessary:

@Override public boolean layoutDependsOn ( CoordinatorLayout parent , FloatingActionButton child , View dependency ) { return dependency instanceof Snackbar . SnackbarLayout ; }

The layoutDependsOn method is CoordinatorLayout ’s way to see which views your floating action button are dependent on. In this case, if the view is a snackbar, set up a dependency by returning true.

The Android documentation indicates that by setting up this dependency, you will receive calls to onDependentViewChanged when a dependent view changes its size or position. This is true, but CoordinatorLayout ’s source provides more detail. onDependentViewChanged is called whenever ViewTreeObserver.OnPreDrawListener.onPreDraw is called or when a scroll or fling action occurs.

@Override public boolean onDependentViewChanged ( CoordinatorLayout parent , FloatingActionButton child , View dependency ) { float translationY = getFabTranslationYForSnackbar ( parent , child ); float percentComplete = - translationY / dependency . getHeight (); float scaleFactor = 1 - percentComplete ; child . setScaleX ( scaleFactor ); child . setScaleY ( scaleFactor ); return false ; }