Material design is a comprehensive guide for visual, motion, and interaction design across platforms and devices. In this codelab, you'll learn the principles of this design language by building a sample Android app.

What you'll learn

What you'll need

* Android devices running Android 2.3.3 (Gingerbread, API Level 10) or higher may be used, however, some material design effects, such as the ripple effect, will not be visible on devices running on Android 4.4 (KitKat) or before.

Download the sample app

You can either download all the sample code to your computer...

Download Zip

...or clone the GitHub repository from the command line.

$ git clone https://github.com/googlecodelabs/android-design-library.git

Run the sample app

First, let's see what the finished sample app looks like. With the code downloaded, the following instructions describe how to open the completed sample app in Android Studio.

  1. Import entire android-design-library package.
  2. Select the 1-Base directory from the sample code folder (Quickstart > Import Project... > 1-Base).
  3. Click the Gradle sync button.
  4. Enable USB debugging on your Android device.
  5. Plug in your Android device and click the Run button. You should see the App home screen appear after a few seconds.

Frequently asked questions

Let's jump right into two key features of material design: Themes and Colors!

Themes let you apply a consistent tone to an app, and developers can choose between dark or light themes (see Figure 1 and Figure 2).

Custom colors can also be defined using theme attributes which are then automatically used by the app for different components e.g colorPrimaryDark for the Status Bar and colorPrimary for the App Bar (see Figure 3 below).

  1. Add the Light theme to our app and customize some of the colors in res/values/styles.xml

styles.xml

<resources>
    <!-- Base application theme. -->
    <style name="AppTheme.Base" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">#3F51B5</item>
        <!-- Light Indigo -->
        <item name="colorPrimaryDark">#3949AB</item>
        <!-- Dark Indigo -->
        <item name="colorAccent">#00B0FF</item>
        <!-- Blue -->
    </style>
    <style name="AppTheme" parent="AppTheme.Base"></style>
</resources>

By using attribute parent="Theme.AppCompat.Light.NoActionBar" will remove ActionBar from app.

The app should now look like this:

In this step you'll create the basic skeleton of an app, which you'll fill in later by adding material design components.

Add a toolbar

Now you're ready to build on top of the starter project.

  1. Add a toolbar and tabs to your app activity_main.xml and MainActivity.java
  2. Delete TextView and add Toolbar in activity_main.xml

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        app:layout_scrollFlags="scroll|enterAlways"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

</RelativeLayout>

MainActivity.java

  1. Import android.support.v7.widget.Toolbar at MainActivity.java and add following codes to add Toolbar to Main screen.
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        // Adding Toolbar to Main screen
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

Add tabs to the toolbar

For this codelab we are using CoordinatorLayout as a container for child views such as TabLayout and FloatingActionButton.

  1. In activity_main.xml remove RelativeLayout and replace with CoordinatorLayout.

  1. In order to use Tabs, we will use TabLayout. First we will create AppBarLayout then we will place ToolbarLayout and TabLayout within AppBarLayout . You can see code samples from below.

activity_main.xml

<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

        <android.support.design.widget.AppBarLayout
            android:id="@+id/appbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="?attr/colorPrimary"
                app:layout_scrollFlags="scroll|enterAlways"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

            <android.support.design.widget.TabLayout
                android:id="@+id/tabs"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />

        </android.support.design.widget.AppBarLayout>
    </android.support.design.widget.CoordinatorLayout>

MainActivity.java

  1. Import android.support.design.widget.TabLayout.
  2. In MainActivity.java and add following codes within onCreate method to create tabs.
 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TabLayout tabs = (TabLayout) findViewById(R.id.tabs);
        tabs.addTab(tabs.newTab().setText("Tab 1"));
        tabs.addTab(tabs.newTab().setText("Tab 2"));
        tabs.addTab(tabs.newTab().setText("Tab 3"));
    }

The app should now look like this:

Add Fragment and ViewPager

Let's add individual views to the tabs so that when you move between tabs you can have different layouts.

  1. Create 3 Fragment java files. ListContentFragment.java , TileContentFragment.java and CardContentFragment.java .

  1. Once we created 3 different Fragments files we will now use ViewPager and Adapter to make the content scrollable. In MainActivity.java create a ViewPager variable and Adapter.

MainActivity.java

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // Adding Toolbar to Main screen
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        // Setting ViewPager for each Tabs
        ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
        setupViewPager(viewPager);
        // Set Tabs inside Toolbar
        TabLayout tabs = (TabLayout) findViewById(R.id.tabs);
        tabs.setupWithViewPager(viewPager);
    }
    // Add Fragments to Tabs
    private void setupViewPager(ViewPager viewPager) {
        Adapter adapter = new Adapter(getSupportFragmentManager());
        adapter.addFragment(new ListContentFragment(), "List");
        adapter.addFragment(new TileContentFragment(), "Tile");
        adapter.addFragment(new CardContentFragment(), "Card");
        viewPager.setAdapter(adapter);
    }

    static class Adapter extends FragmentPagerAdapter {
        private final List<Fragment> mFragmentList = new ArrayList<>();
        private final List<String> mFragmentTitleList = new ArrayList<>();

        public Adapter(FragmentManager manager) {
            super(manager);
        }

        @Override
        public Fragment getItem(int position) {
            return mFragmentList.get(position);
        }

        @Override
        public int getCount() {
            return mFragmentList.size();
        }

        public void addFragment(Fragment fragment, String title) {
            mFragmentList.add(fragment);
            mFragmentTitleList.add(title);
        }

        @Override
        public CharSequence getPageTitle(int position) {
            return mFragmentTitleList.get(position);
        }
    }
  1. In activity_main.xml add a ViewPager element outside of AppBarLayout so that AppBar will stay on top of screen while scrolling the views.

activity_main.xml

</android.support.design.widget.AppBarLayout>
    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />
  1. Create a file defining the layout of each view item_list.xml, item_tile.xml and item_card.xml under res/layout/. Take a look at the individual attributes to see what customizations are available.

Your app should now look like this:

RecyclerView is a container for displaying large data sets that can be scrolled very efficiently by maintaining a limited number of views. Our data set for this codelab is comprised of empty cards which are pieces of paper that serve as an entry point to more information.

Let's add a RecyclerView to our app:

  1. Add dependencies to build.gradle to use CardView and RecyclerView.

build.gradle

dependencies {
    compile 'com.android.support:appcompat-v7:23.4.0'
    compile 'com.android.support:design:23.4.0'
    compile 'com.android.support:cardview-v7:23.4.0'
    compile 'com.android.support:recyclerview-v7:23.4.0'
}
  1. Create recycler_view.xml under the res/layout folder.

recycler_view.xml

<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/my_recycler_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipToPadding="false"
    android:paddingBottom="@dimen/md_keylines"
    android:paddingTop="@dimen/md_keylines"
    android:scrollbars="vertical"
    app:layout_behavior="@string/appbar_scrolling_view_behavior" />
  1. In each fragment, create and customize the RecyclerView. Start by extending RecyclerView.ViewHolder. Replace R.layout.item_tile as appropriate, to match the view used in each fragment.
public static class ViewHolder extends RecyclerView.ViewHolder {
    public ViewHolder(LayoutInflater inflater, ViewGroup parent) {
        super(inflater.inflate(R.layout.item_tile, parent, false));
    }
}
  1. In each fragment, create a RecyclerView.Adapter instance, wrapping the ViewHolder that was just created.
public static class ContentAdapter extends RecyclerView.Adapter<ViewHolder> {
    // Set numbers of List in RecyclerView.
    private static final int LENGTH = 18;

    public ContentAdapter() {
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new ViewHolder(LayoutInflater.from(parent.getContext()), parent);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        // no-op
    }

    @Override
    public int getItemCount() {
        return LENGTH;
    }
}
  1. For each fragment, update onCreateView() to use the new ContentAdapter.

    Specifically for TileContentFragment, let's also take a moment to adjust the padding and tell RecyclerView to use a GridLayout — this will make things look nicer, since our tiles will be small.
public class TileContentFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        RecyclerView recyclerView = (RecyclerView) inflater.inflate(
                R.layout.recycler_view, container, false);
        ContentAdapter adapter = new ContentAdapter();
        recyclerView.setAdapter(adapter);
        recyclerView.setHasFixedSize(true);
        
        // Set padding for Tiles (not needed for Cards/Lists!)
        int tilePadding = getResources().getDimensionPixelSize(R.dimen.tile_padding);
        recyclerView.setPadding(tilePadding, tilePadding, tilePadding, tilePadding);
        recyclerView.setLayoutManager(new GridLayoutManager(getActivity(), 2));

        return recyclerView;
    }

If you need help, take a look at TileContentFragment.java, ListContentFragment.java, and CardContentFragment.java. Your app should now look like this:

  1. To complete the effect, let's style each view by modifying item_list.xml, item_tile.xml to include an image.

    We'll also do the same for item_card.xml, wrapping our RelativeLayout inside a CardView so that we can get the shadows and rounded-corners typical of a card. (On Lollipop or newer devices, shadows is accomplished using Android's native elevation property. On older devices, the support library simulates the effect using drawables.)

Your app should now look like this:

In this step you'll learn how to use VectorDrawable by using Support Library support-vector-drawable. You'll be able to use VectorDrawableCompat back to API 7 device. By using vector assets app only need single vector assets for multiple device screen.

Adding config to gradle file

Add following new attribute

build.gradle

// Gradle Plugin 2.0+  
 android {  
   defaultConfig {  
     vectorDrawables.useSupportLibrary = true  
    }  
 }  

Import Vector Assets to Android Studio

To import vector assets to Android Studio, press CTRL + Enter at drawable directory and choose New -> Vector Asset.

For this codelab we will import favorite and share vector assets to style cards.

Once you import vector assets, you can now use app:srcCompat instead of android:src to render images within cards by using vector support library.

item_card.xml

<ImageButton
            android:id="@+id/share_button"
            android:layout_width="@dimen/cards_button_width"
            android:layout_height="@dimen/cards_button_height"
            android:layout_marginRight="@dimen/md_keylines"
            app:srcCompat="@drawable/ic_share"
            android:layout_below="@+id/card_text"
            android:layout_alignParentRight="true"
            style="?android:attr/borderlessButtonStyle"
            android:tint="@color/button_grey" />

Your app should now look like this:

You can notice that we have favorite and share icons within card.

Add a NavigationDrawer

The navigation drawer slides in from the left. It is a common pattern found in Google apps and follows the keylines and metrics for lists.

  1. Create a file menu_navigation.xml defining the navigation items under res/menu folder.

menu_navigation.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <group android:checkableBehavior="single">
        <item
            android:icon="@drawable/ic_home_black_24dp"
            android:tint="@color/button_grey"
            android:title="One" />
        <item
            android:icon="@drawable/ic_favorite_black_24dp"
            android:tint="@color/button_grey"
            android:title="Two" />
        <item
            android:icon="@drawable/ic_bookmark_border_black_24dp"
            android:tint="@color/button_grey"
            android:title="Three" />
    </group>
</menu>
  1. Create a file navheader.xml defining a Navigation Drawer material under the res/layout/ folder.

navheader.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="@dimen/navheader_height"
    android:background="?attr/colorPrimaryDark"
    android:orientation="vertical"
    android:padding="@dimen/md_keylines">
</LinearLayout>
  1. In activity_main.xml:

activity_main.xml

<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/drawer"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

activity_main.xml

<android.support.design.widget.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true"
        app:headerLayout="@layout/navheader"
        app:menu="@menu/menu_navigation" />
  1. In MainActivity.java:
private DrawerLayout mDrawerLayout;
// Create Navigation drawer and inflate layout
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer);

// Adding menu icon to Toolbar
ActionBar supportActionBar = getSupportActionBar();
if (supportActionBar != null) {
    supportActionBar.setHomeAsUpIndicator(R.drawable.ic_menu_white_24dp);
    supportActionBar.setDisplayHomeAsUpEnabled(true);
}

// Set behavior of Navigation drawer
navigationView.setNavigationItemSelectedListener(
    new NavigationView.OnNavigationItemSelectedListener() {
        // This method will trigger on item Click of navigation menu
        @Override
        public boolean onNavigationItemSelected(MenuItem menuItem) {
            // Set item in checked state
            menuItem.setChecked(true);
            // TODO: handle navigation
            // Closing drawer on item click
            mDrawerLayout.closeDrawers();
            return true;
        }
    });
@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();
    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    } else if (id == android.R.id.home) {
        mDrawerLayout.openDrawer(GravityCompat.START);
    }
    return super.onOptionsItemSelected(item);
}

Add a Floating Action Button (FAB) and trigger a SnackBar

Floating action buttons are used for a promoted action and are distinguished by a circled icon floating above the UI. Let's create a FAB that triggers a SnackBar which provides lightweight feedback about an operation by showing a brief message.

  1. In activity_main.xml add a FloatingActionButton to the end of the CoordinatorLayout.
  2. In MainActivity.java, add a Listener to the FAB that creates a SnackBar onclick

activity_main.xml

<android.support.design.widget.FloatingActionButton
            android:id="@+id/fab"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="right|bottom"
            android:layout_marginBottom="@dimen/md_keylines"
            android:layout_marginRight="@dimen/md_keylines"
            android:src="@drawable/ic_add_white_24dp" />

MainActivity.java

// Adding Floating Action Button to bottom right of main view
        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Snackbar.make(v, "Hello Snackbar!",
                        Snackbar.LENGTH_LONG).show();
            }
        });
  1. In values-v21 folder, update styles.xml to create system bar transparent for device running Android 5 and above.

styles.xml

<resources>
    <style name="AppTheme" parent="AppTheme.Base">
        <item name="android:windowDrawsSystemBarBackgrounds">true</item>
        <item name="android:statusBarColor">@android:color/transparent</item>
    </style>
</resources>
  1. InCardContentFragment.java file add methods when buttons within card pressed shows snackbar.

Your app should now look like this:

Create a Detail View

Use an Intent to allow users to move between cards and detail views. Let's create a detail view in our app:

  1. Create DetailActivity.java and activity_detail.xml.
  2. Create a new Intent within each of ListContentFragment.java, TileContentFragment.java, and CardContentFragment.java so that each item has a link to the detailed view.
public static class ViewHolder extends RecyclerView.ViewHolder {
    public ViewHolder(LayoutInflater inflater, ViewGroup parent) {
        super(inflater.inflate(R.layout.item_list, parent, false));
        itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Context context = v.getContext();
                Intent intent = new Intent(context, DetailActivity.class);
                context.startActivity(intent);
            }
        });
    }
}
  1. In order to have your activity show up make sure to add the activity to the AndroidManifest.xml file.

AndroidManifest.xml

<activity
    android:name=".DetailActivity"
    android:parentActivityName=".MainActivity">
    <meta-data
        android:name="android.support.PARENT_ACTIVITY"
        android:value=".MainActivity" />
</activity>

Switch to a Collapsing Toolbar

A Collapsing Toolbar provides visual transitions by collapsing a toolbar as the user scrolls down the app. Let's go ahead and add a collapsing toolbar:

  1. In activity_detail.xml, add an AppBarLayout and CollapsingToolbarLayout within CoordinatorLayout.

activity_detail.xml

<android.support.design.widget.AppBarLayout
    android:id="@+id/appbar"
    android:layout_width="match_parent"
    android:layout_height="@dimen/app_bar_height"
    android:fitsSystemWindows="true"
    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

    <android.support.design.widget.CollapsingToolbarLayout
        android:id="@+id/collapsing_toolbar"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        android:theme="@style/ThemeOverlay.AppCompat.Dark"
        app:contentScrim="?attr/colorPrimary"
        app:expandedTitleMarginEnd="@dimen/article_keylines"
        app:expandedTitleMarginStart="@dimen/md_keylines"
        app:layout_scrollFlags="scroll|exitUntilCollapsed">

        <ImageView
            android:id="@+id/image"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@drawable/paris"
            android:fitsSystemWindows="true"
            android:scaleType="centerCrop"
            app:layout_collapseMode="parallax" />

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:layout_collapseMode="pin"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

    </android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
  1. In DetailActivity.java set the title of the collapsing toolbar's detail view.

DetailActivity.java

// Set Collapsing Toolbar layout to the screen
CollapsingToolbarLayout collapsingToolbar =
        (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
// Set title of Detail page
collapsingToolbar.setTitle(getString(R.string.item_title));

Congratulations, you're finished! You're now ready to create a material design app.

When you have a spare moment, we'd really appreciate if you could fill out some feedback on your codelab experience. We'll use this information to iterate and improve the codelab over time.

TELL US HOW WE DID

What we covered

Next Steps

Now it's time to add material design to your own app.

Learn More