Mobile Development 18 min read

Understanding Material Design: Concepts, Components, and Animation Implementations in Android

Material Design, Google’s visual language built on paper‑like metaphors, depth, and purposeful animation, defines a three‑dimensional environment with elevation and shadows, while Android’s libraries such as CoordinatorLayout, AppBarLayout, DrawerLayout, and ActivityOptionsCompat provide concrete components and behaviors—like toolbar hide‑on‑scroll, navigation‑drawer toggling, and shared‑element transitions—to implement these concepts in apps.

Tencent Music Tech Team
Tencent Music Tech Team
Tencent Music Tech Team
Understanding Material Design: Concepts, Components, and Animation Implementations in Android

Part 1: What is Material Design

Material Design was introduced by Google at the I/O conference in 2014 and has been evolving for more than two years. It follows a visual language based on paper and ink, bringing physical motion into UI design. Google describes it as a visual design language built on a set of fundamental rules, encompassing both design specifications and an underlying system of APIs and open‑source libraries that follow the Material style.

The term is translated in many ways (material design, essence design, etc.), but “original‑material design” best captures its intent: treating UI elements as a new material with physical properties similar to paper and ink, rather than a purely flat or skeuomorphic approach.

Material Design emphasizes three core aspects:

Physical metaphor (depth and elevation).

Clear, meaningful visual representation that reflects user intent.

Purposeful animation.

The foundation consists of three parts: the environment, Material attributes, and elevation/shadow.

1. Environment

UI objects exist in a three‑dimensional coordinate system (x, y, z). While the screen is essentially a 2‑D plane, the added z‑axis enables layering, depth, and more complex interactions. Each Material element occupies a position on the z‑axis with a default thickness of 1dp.

Light and shadow are essential: a primary light source casts directional shadows, while ambient light creates soft, consistent shading.

2. Material Attributes

A Material is defined as an immutable entity with fixed behavior. Its width and height can change freely, but its thickness remains uniform (1dp). Materials can be stretched, raised, or disappear anywhere in the environment.

3. Elevation

Elevation measures the relative depth of an element along the z‑axis, expressed in dp. It determines both static height and dynamic height changes during interaction. Various UI components have reference elevation values that guide designers.

4. Shadow

Shadows convey depth and directional movement, providing visual cues about the distance between layers.

5. Reference Shadow Parameters

Designers should follow the standard shadow parameters provided by Google when implementing components.

Part 2: Material Design Components and Animation Summary

CoordinatorLayout + AppBarLayout + Toolbar + DrawerLayout – Toolbar Hide on Scroll

This pattern uses CoordinatorLayout , a super‑powered FrameLayout , to coordinate scrolling and animation between child views via Behavior objects.

Key points:

Acts as a top‑level layout manager.

Enables interaction between multiple child views.

Behaviors are instantiated via reflection from the app:layout_behavior attribute. Example of behavior resolution:

mBehaviorResolved = a.hasValue(R.styleable.CoordinatorLayout_LayoutParams_layout_behavior);
if (mBehaviorResolved) {
    mBehavior = parseBehavior(context, attrs, a.getString(
        R.styleable.CoordinatorLayout_LayoutParams_layout_behavior));
}

The onStartNestedScroll method determines whether a child view participates in nested scrolling:

public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes){
    boolean handled = false;
    final int childCount = getChildCount();
    for (int i = 0; i < childCount; i++) {
        final View view = getChildAt(i);
        final LayoutParams lp = (LayoutParams) view.getLayoutParams();
        final Behavior viewBehavior = lp.getBehavior();
        if (viewBehavior != null) {
            final boolean accepted = viewBehavior.onStartNestedScroll(this, view, child, target,
                nestedScrollAxes);
            handled |= accepted;
            lp.acceptNestedScroll(accepted);
        } else {
            lp.acceptNestedScroll(false);
        }
    }
    return handled;
}

AppBarLayout’s onStartNestedScroll checks for vertical scrolling and the presence of scrollable children:

public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child,
        View directTargetChild, View target, int nestedScrollAxes) {
    final boolean started = (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0
            && child.hasScrollableChildren()
            && parent.getHeight() - directTargetChild.getHeight() <= child.getHeight();
    if (started && mAnimator != null) {
        mAnimator.cancel();
    }
    mLastNestedScrollingChildRef = null;
    return started;
}

When a child view scrolls, the Toolbar can be hidden or revealed based on the app:layout_scrollFlags values such as scroll , enterAlways , enterAlwaysCollapsed , and exitUntilCollapsed .

Example layout XML:

<android.support.design.widget.CoordinatorLayout 
    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="com.example.vienwang.applayouttoolbar.MainActivity">
    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">
        <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/AppTheme.PopupOverlay" />
    </android.support.design.widget.AppBarLayout>
    <include layout="@layout/content_main" />
    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end" />
</android.support.design.widget.CoordinatorLayout>

DrawerLayout + ActionBarDrawerToggle – Navigation Drawer

The ActionBarDrawerToggle wraps DrawerLayout to provide three main functions: listening to drawer state changes, animating the hamburger‑to‑arrow icon, and handling the home button click.

Key method:

public void syncState() {
    if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
        mSlider.setPosition(1);
    } else {
        mSlider.setPosition(0);
    }
    if (mDrawerIndicatorEnabled) {
        setActionBarUpIndicator((Drawable) mSlider,
            mDrawerLayout.isDrawerOpen(GravityCompat.START) ?
                mCloseDrawerContentDescRes : mOpenDrawerContentDescRes);
    }
}

ActivityOptionsCompat – Shared Element Transition

Shared‑element transitions create seamless animations between activities. Example usage:

ActivityOptionsCompat activityOptions = ActivityOptionsCompat.makeSceneTransitionAnimation(
        this,
        new Pair
(view.findViewById(R.id.imageview_item),
            DetailActivity.VIEW_NAME_HEADER_IMAGE),
        new Pair
(view.findViewById(R.id.textview_name),
            DetailActivity.VIEW_NAME_HEADER_TITLE));
ActivityCompat.startActivity(this, intent, activityOptions.toBundle());

The underlying implementation builds arrays of views and transition names, then creates an ActivityOptions object that manages the exit transition coordinator:

public static ActivityOptions makeSceneTransitionAnimation(Activity activity,
        Pair
... sharedElements) {
    ActivityOptions opts = new ActivityOptions();
    if (!activity.getWindow().hasFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)) {
        opts.mAnimationType = ANIM_DEFAULT;
        return opts;
    }
    opts.mAnimationType = ANIM_SCENE_TRANSITION;
    ArrayList
names = new ArrayList
();
    ArrayList
views = new ArrayList
();
    if (sharedElements != null) {
        for (int i = 0; i < sharedElements.length; i++) {
            Pair
sharedElement = sharedElements[i];
            String sharedElementName = sharedElement.second;
            if (sharedElementName == null) {
                throw new IllegalArgumentException("Shared element name must not be null");
            }
            names.add(sharedElementName);
            View view = sharedElement.first;
            if (view == null) {
                throw new IllegalArgumentException("Shared element must not be null");
            }
            views.add(view);
        }
    }
    ExitTransitionCoordinator exit = new ExitTransitionCoordinator(activity, names, names,
            views, false);
    opts.mTransitionReceiver = exit;
    opts.mSharedElementNames = names;
    opts.mIsReturning = false;
    opts.mExitCoordinatorIndex = activity.mActivityTransitionState.addExitTransitionCoordinator(exit);
    return opts;
}

Material Design’s animation style is clean yet diverse, offering a user‑centric experience. While Google’s official libraries cover many common cases, developers often need to fine‑tune or create custom animations to match the design specifications.

mobile developmentanimationAndroid UICoordinatorLayoutMaterial Design
Tencent Music Tech Team
Written by

Tencent Music Tech Team

Public account of Tencent Music's development team, focusing on technology sharing and communication.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.