Posted by Ian Lake, Developer Advocate
Android 5.0 Lollipop was one of the most significant Android releases ever, in no small part due to the introduction of material design, a new design language that refreshed the entire Android experience. Our detailed spec is a great place to start to adopt material design, but we understand that it can be a challenge for developers, particularly ones concerned with backward compatibility. With a little help from the new Android Design Support Library, we’re bringing a number of important material design components to all developers and to all Android 2.1 or higher devices. You’ll find a navigation drawer view, floating labels for editing text, a floating action button, snackbar, tabs, and a motion and scroll framework to tie them together.
The navigation drawer can be an important focal point for identity and navigation within your app and consistency in the design here can make a considerable difference in how easy your app is to navigate, particularly for first time users.
NavigationView makes this easier by providing the framework you need for the navigation drawer as well as the ability to inflate your navigation items through a menu resource.
DrawerLayout’s drawer content view with a layout such as:
<android.support.v4.widget.DrawerLayout 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:fitsSystemWindows="true"> <!-- your content layout --> <android.support.design.widget.NavigationView android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" app:headerLayout="@layout/drawer_header" app:menu="@menu/drawer"/> </android.support.v4.widget.DrawerLayout>
You’ll note two attributes for
NavigationView: app:headerLayout controls the (optional) layout used for the header.
app:menu is the menu resource inflated for the navigation items (which can also be updated at runtime).
NavigationView takes care of the scrim protection of the status bar for you, ensuring that your
NavigationView interacts with the status bar appropriately on API21+ devices.
The simplest drawer menus will be a collection of checkable menu items:
<group android:checkableBehavior="single"> <item android:id="@+id/navigation_item_1" android:checked="true" android:icon="@drawable/ic_android" android:title="@string/navigation_item_1"/> <item android:id="@+id/navigation_item_2" android:icon="@drawable/ic_android" android:title="@string/navigation_item_2"/> </group>
The checked item will appear highlighted in the navigation drawer, ensuring the user knows which navigation item is currently selected.
You can also use subheaders in your menu to separate groups of items:
<item android:id="@+id/navigation_subheader" android:title="@string/navigation_subheader"> <menu> <item android:id="@+id/navigation_sub_item_1" android:icon="@drawable/ic_android" android:title="@string/navigation_sub_item_1"/> <item android:id="@+id/navigation_sub_item_2" android:icon="@drawable/ic_android" android:title="@string/navigation_sub_item_2"/> </menu> </item>
You’ll get callbacks on selected items by setting a
setNavigationItemSelectedListener(). This provides you with the
MenuItem that was clicked, allowing you to handle selection events, changed the checked status, load new content, programmatically close the drawer, or any other actions you may want.
Floating labels for editing text
Even the humble
EditText has room to improve in material design. While an
EditText alone will hide the hint text after the first character is typed, you can now wrap it in a
TextInputLayout, causing the hint text to become a floating label above the
EditText, ensuring that users never lose context in what they are entering.
In addition to showing hints, you can also display an error message below the
EditText by calling
Floating Action Button
A floating action button is a round button denoting a primary action on your interface. The Design library’s
FloatingActionButton gives you a single consistent implementation, by default colored using the
colorAccent from your theme.
In addition to the normal size floating action button, it also supports the mini size (
fabSize="mini") when visual continuity with other elements is critical. As
ImageView, you’ll use
android:src or any of the methods such as
setImageDrawable() to control the icon shown within the
Providing lightweight, quick feedback about an operation is a perfect opportunity to use a snackbar. Snackbars are shown on the bottom of the screen and contain text with an optional single action. They automatically time out after the given time length by animating off the screen. In addition, users can swipe them away before the timeout.
By including the ability to interact with the
Snackbar through swiping it away or actions, these are considerably more powerful than toasts, another lightweight feedback mechanism. However, you’ll find the API very familiar:
Snackbar .make(parentLayout, R.string.snackbar_text, Snackbar.LENGTH_LONG) .setAction(R.string.snackbar_action, myOnClickListener) .show(); // Don’t forget to show!
You’ll note the use of a
View as the first parameter to
make() - Snackbar will attempt to find an appropriate parent of the
Snackbar’s view to ensure that it is anchored to the bottom.
Switching between different views in your app via tabs is not a new concept to material design and they are equally at home as a top level navigation pattern or for organizing different groupings of content within your app (say, different genres of music).
The Design library’s
TabLayout implements both fixed tabs, where the view’s width is divided equally between all of the tabs, as well as scrollable tabs, where the tabs are not a uniform size and can scroll horizontally. Tabs can be added programmatically:
TabLayout tabLayout = ...; tabLayout.addTab(tabLayout.newTab().setText("Tab 1"));
However, if you are using a
ViewPager for horizontal paging between tabs, you can create tabs directly from your
getPageTitle() and then connect the two together using
setupWithViewPager(). This ensures that tab selection events update the
ViewPager and page changes update the selected tab.
CoordinatorLayout, motion, and scrolling
Distinctive visuals are only one part of material design: motion is also an important part of making a great material designed app. While there are a lot of parts of motion in material design including touch ripples and meaningful transitions, the Design library introduces
CoordinatorLayout, a layout which provides an additional level of control over touch events between child views, something which many of the components in the Design library take advantage of.
CoordinatorLayout and floating action buttons
A great example of this is when you add a
FloatingActionButton as a child of your
CoordinatorLayout and then pass that
CoordinatorLayout to your
Snackbar.make() call - instead of the snackbar displaying over the floating action button, the
FloatingActionButton takes advantage of additional callbacks provided by
CoordinatorLayout to automatically move upward as the snackbar animates in and returns to its position when the snackbar animates out on Android 3.0 and higher devices - no extra code required.
CoordinatorLayout also provides an
layout_anchor attribute which, along with
layout_anchorGravity, can be used to place floating views, such as the
FloatingActionButton, relative to other views.
CoordinatorLayout and the app bar
The other main use case for the
CoordinatorLayout concerns the app bar (formerly action bar) and scrolling techniques. You may already be using a
Toolbar in your layout, allowing you to more easily customize the look and integration of that iconic part of an app with the rest of your layout. The Design library takes this to the next level: using an
AppBarLayout allows your
Toolbar and other views (such as tabs provided by
TabLayout) to react to scroll events in a sibling view marked with a
ScrollingViewBehavior. Therefore you can create a layout such as:
<android.support.design.widget.CoordinatorLayout 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"> <! -- Your Scrollable View --> <android.support.v7.widget.RecyclerView android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <android.support.v7.widget.Toolbar ... app:layout_scrollFlags="scroll|enterAlways"> <android.support.design.widget.TabLayout ... app:layout_scrollFlags="scroll|enterAlways"> </android.support.design.widget.AppBarLayout> </android.support.design.widget.CoordinatorLayout>
Now, as the user scrolls the
AppBarLayout can respond to those events by using the children’s scroll flags to control how they enter (scroll on screen) and exit (scroll off screen). Flags include:
scroll: this flag should be set for all views that want to scroll off the screen - for views that do not use this flag, they’ll remain pinned to the top of the screen
enterAlways: this flag ensures that any downward scroll will cause this view to become visible, enabling the ‘quick return’ pattern
enterAlwaysCollapsed: When your view has declared a minHeight and you use this flag, your View will only enter at its minimum height (i.e., ‘collapsed’), only re-expanding to its full height when the scrolling view has reached it’s top.
exitUntilCollapsed: this flag causes the view to scroll off until it is ‘collapsed’ (its minHeight) before exiting
One note: all views using the
scroll flag must be declared before views that do not use the flag. This ensures that all views exit from the top, leaving the fixed elements behind.
Toolbar directly to an
AppBarLayout gives you access to the
exitUntilCollapsed scroll flags, but not the detailed control on how different elements react to collapsing. For that, you can use
<android.support.design.widget.AppBarLayout android:layout_height="192dp" android:layout_width="match_parent"> <android.support.design.widget.CollapsingToolbarLayout android:layout_width="match_parent" android:layout_height="match_parent" app:layout_scrollFlags="scroll|exitUntilCollapsed"> <android.support.v7.widget.Toolbar android:layout_height="?attr/actionBarSize" android:layout_width="match_parent" app:layout_collapseMode="pin"/> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout>
This setup uses
app:layout_collapseMode="pin" to ensure that the Toolbar itself remains pinned to the top of the screen while the view collapses. Even better, when you use
Toolbar together, the title will automatically appear larger when the layout is fully visible, then transition to its default size as it is collapsed. Note that in those cases, you should call
setTitle() on the
CollapsingToolbarLayout, rather than on the Toolbar itself.
In addition to pinning a view, you can use
app:layout_collapseMode="parallax" (and optionally
app:layout_collapseParallaxMultiplier="0.7" to set the parallax multiplier) to implement parallax scrolling (say of a sibling
ImageView within the
CollapsingToolbarLayout). This use case pairs nicely with the
app:contentScrim="?attr/colorPrimary" attribute for
CollapsingToolbarLayout, adding a full bleed scrim when the view is collapsed.
CoordinatorLayout and custom views
One thing that is important to note is that
CoordinatorLayout doesn’t have any innate understanding of a
AppBarLayout work - it just provides an additional API in the form of a
Coordinator.Behavior, which allows child views to better control touch events and gestures as well as declare dependencies between each other and receive callbacks via
Views can declare a default Behavior by using the
CoordinatorLayout.DefaultBehavior(YourView.Behavior.class) annotation,or set it in your layout files by with the
app:layout_behavior="com.example.app.YourView$Behavior" attribute. This framework makes it possible for any view to integrate with
The Design library is available now, so make sure to update the Android Support Repository in the SDK Manager. You can then start using the Design library with a single new dependency:
Note that as the Design library depends on the Support v4 and AppCompat Support Libraries, those will be included automatically when you add the Design library dependency. We also took care that these new widgets are usable in the Android Studio Layout Editor’s Design view (find them under CustomView), giving you an easier way to preview some of these new components.
The Design library, AppCompat, and all of the Android Support Library are important tools in providing the building blocks needed to build a modern, great looking Android app without building everything from scratch.