Exploring Android Material Components

Exploring Android Material Components

Image source: material.io

Recently, Google published a new version of the Material Design Guidelines that features enhanced support for integration of the principles for the community. Additional resources of interest are fancy sample projects called Material Studies that mimic real-world apps, a brand new Sketch plugin for generating Material themes and styles, and a new Material Components library that intends to replace the old Design Support Library.

As you’ve probably heard, Android Support Library 28 will be the final version deployed, and we’ll move directly into the AndroidX APIs (JetPack) once and for all.

At 47 Degrees, we care about the quality of the products we work on for ourselves, as well as our clients, so we assume it’s a good time to start exploring JetPack to get ahead of any problems.

There’s an abundance of tutorials out there for migrating your entire app to JetPack (AndroidX namespace) beginning with the official tutorial and followed by a few interesting articles that highlight some caveats you might find during the process. Here are a few to check out:

We’ll probably write about migrating at some point as well since we’ll likely suffer through that process like everyone else.

Material components

For our purposes, let’s focus on the new Material Design Components initiative, an effort by the Google team, not Android since it’s part of the global Material Design Initiative that has support for a variety of platforms.

The official Material.io site, along with the material-components GitHub organization, contain all the project’s docs. When you open the GitHub org, you’ll find multiple implementations of the same concept for different platforms including repos for Android, iOS, Web, React (a wrapper for the web platform), and Flutter which was just released recently.

We’ll only be focusing on the Android version since that’s the platform we’ll be putting this into practice with first.

What does it replace?

Material Components for Android is essentially a direct replacement for the old Design Support Library, so it still provides all the components that previously belonged to the mentioned artifact i.e., ChipView. The only differences are the packaging and dependency on AndroidX APIs.

This library can also be considered a wrapper over AppCompat, so you’ll find a bunch of themes and styles that you can inherit from, or apply, to any of your AppCompat widgets. It should be noted that, when we say “wrapper” here, we just mean that it’s transitively depending on AppCompat since all of it’s themes and styles are inherited from it.

If you want, you can try to completely remove the AppCompat artifact dependency from your project since it’s transitively provided by the Material Components dependency. Note that it’s also valid to explicitly provide a dependency if you want to enforce a given version. In this case, please remember to use the AndroidX dependency.

dependencies {
    implementation "androidx.appcompat:appcompat:$rootProject.appCompatVersion"
}

Material Components is not a replacement for AppCompat, which has additional responsibilities like replacing widgets with their AppCompat equivalents at compile time. Still, it should be noted that Material Components extends the AppCompatViewInflater which is the class that’s in charge of making these replacements. The goal is to override certain methods to provide proper Material-themed component replacements. (i.e., MaterialButton) for standard widgets like Buttons, CheckBoxes, and RadioButtons.

Integration

Material Components for Android has been out for some time now, and there’s a detailed guide on how to integrate the dependency in your project step-by-step.

As mentioned previously, the Material Components library is tied to AndroidX. If you’re not quite ready to make the switch over to JetPack, there are similar themes and widgets for Design Support 28.

Google intentionally deployed 1.0.0 for all of their JetPack artifacts with equivalent public APIs as Design Support 28, so the difference between the new and old artifacts are essentially different namespaces (support vs. androidx).

Obviously, this will not include any widgets or styles released in future versions of the Material Components artifact from here on out, but it serves as a starting point for a migration. For instance, first, you could upgrade your app to Support 28, then port everything to JetPack 1.0.0 APIs. It’s also an excellent way to segregate your efforts and adequately estimate your roadmap.

Please note that compileSdkVersion must be version 28 to use this library.

Components

For all Material Components views, the namespace will be com.google.android.material. Make sure you don’t use any support namespaces for those and always double-check when adding new ones.

com.google.android.material.textfield.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="@string/textfield_label">

  <com.google.android.material.textfield.TextInputEditText
      android:layout_width="match_parent"
      android:layout_height="wrap_content"/>
</com.google.android.material.textfield.TextInputLayout>

A complete list of currently available components can be found in the “components” section in the side-bar of the official docs as well as a detailed description of each and xml snippets for using them in your layouts.

All these components (at least for 1.0.0) are also provided by Design Support Library 28. Each of the widgets there use the com.google.android.material namespace and the ones that don’t are replaced at compile time by their “Material” version counterparts.

Theming

For theming, you’ll be required to inherit your AppTheme from MaterialComponents for the same reasons we’ve had to inherit from `AppCompat themes in the past.

There are equivalent “app-level” themes for all of AppCompat’s under the Material Components namespace. So the translation should be one-to-one, i.e.:

<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
    <!-- ... -->
</style>

You can view the available themes on GitHub.

For some constraints on your project, you may not want to inherit from the MaterialComponent themes. In these cases, you can use the Bridge themes instead, though these are mostly for gradual migrations. Detailed explanations of Bridge themes plus snippets on how to use them, can be found here: Bridge Themes

“Bridge themes inherit from AppCompat themes, but also define the new Material Components theme attributes for you.”

Basically, they set defaults for attributes used in MaterialComponents styles. As mentioned previously, there are similar Bridge themes available for each of the MaterialComponents app level themes.

As an ultimate fallback, and in case using Bridge themes is a problem for you, you can keep inheriting from AppCompat, and then manually add a bunch of attributes from Material Components to the style. After personally speaking to the Google team responsible for developing this library, this doesn’t seem to be an ideal situation, and it’s not very maintainable either. The primary use case for this third alternative is if you’re on the edge and need to have full control of “what goes into your theme”, instead of relying on the default Material Design attributes added by the MaterialComponents and Bridge themes. Nevertheless, you can view the docs for this alternative method.

Also note, that you always have the chance to manually apply themes per view, similar to:

<com.google.android.material.textfield.TextInputLayout
    style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="@string/textfield_label">

  <com.google.android.material.textfield.TextInputEditText
      android:layout_width="match_parent"
      android:layout_height="wrap_content"/>
</com.google.android.material.textfield.TextInputLayout>

Material Components provides separate styles for each available component just in case you need them or want to inherit from them. Note that this is not required if you’re applying the suggested app level themes. Even AppCompat ThemeOverlays have been ported over.

Since Material Components is a wrapper over AppCompat, you still require your activities to inherit from AppCompatActivity or, at least use the AppCompatDelegate (in case you can’t inherit), so all your widgets are properly themed using the corresponding MaterialsComponents themes, which inherit from their corresponding AppCompat versions.

Be aware that MaterialComponentsActivity and MaterialComponentsDelegate do not have equivalents, so you need to continue to use the AppCompat versions, at least for now. This is likely because the folks at Google didn’t need to add specifics on top of those.

If you skip this, your standard widgets won’t be replaced by the AppCompat widgets where needed at compile time and you might end up seeing stuff with the wrong styles and behavior.

I highly recommend reading the complete guide about theming and all the new attributes available in the official docs.

You can find most of the new styles for the components listed here, but be aware that some of these add additional styles and are defined in their own package, so it’s hard to link to the complete list. The Google team is thinking of possibly adding these to the docs of each component, which would be very handy in my opinion.

Material Components cheat sheet

Is there a cheat sheet? That’s probably the main question that arises when people start with Material components. I think we’ve covered the bases here, but a cheat sheet could be quite handy.

If your intention is to move to the AndroidX namespace (JetPack), which you definitely should considering that there won’t be new Support Libraries released, you should always try to:

App Theming

  • Inherit your app theme using one of the options from MaterialComponents, like Theme.MaterialComponents.Light.NoActionBar.
  • Otherwise, double check to see if you can inherit a Bridge theme.
  • If neither of these options is possible, and you have to stick with AppCompat themes while you gradually port your app, you can add all of the attributes from Material Components as specified in the Theming section. In case you forget to add a required attribute, Material Components will throw an exception, so you should be safe.

Namespace

  • Ideally, remove any Support Library dependencies from your build.gradle files. At the very least, remove the Design Support dependency to start.
  • Any time you want to add a new View to any of your layouts, check whether it’s provided in the Material Components library (or in other words, previously provided in the Design Support Library). If that’s the case, use the equivalent from Material Components. Always double check that you don’t have any support namespaces for those widgets - this is key in keeping the back door open for removing the support design artifact if you haven’t already.
  • If possible, only use AndroidX and .com.google.android.material. If you can’t upgrade to AndroidX, you should use the old Support Library version 28 for everything. Never mix the two of them, this will cause exceptions to be thrown.
  • Any time you’re going to use an AppCompat style (for a view or an app theme), make sure there isn’t an existing version for Material Components. If there is, you should use it, otherwise, your views will be stylized using the old AppCompat themes.
  • Remember that the AppCompat library will be continued under the AndroidX namespace, so you can continue using it. The dependency is androidx.appcompat:appcompat:version. You can view an example of it’s use in the Sunflower sample app. As mentioned previously, you’ll get the dependency transitively by using the Material Components artifact, in case you don’t want to declare it explicitly.

What if I don’t upgrade?

Android Support libraries exist as an abstraction layer so you can support many different OS versions without changing the code base instead of relying on version dependent features from the Android SDK. This also includes AppCompat.

If you continue to target the old Support libraries, you’ll lose all of the new features released on JetPack as a natural continuation of those, in order to improve the aforementioned abstraction layer. You’d basically be stuck on those APIs forever, or, at least until you get a system update and therefore a new version of the Android SDK.

Final thoughts

I think it’s more than clear that we should start our migrations to the Material Components library sooner rather than later. At 47 Degrees, we had some doubts about when and how to use this artifact, but writing this summary has been both helpful and enriching for us. Hopefully, it proves to be the same for you and your team.

If you’re interested in checking out how the new Material Components look and behave in different scenarios, you can take a look at the Material Components Catalog App.

Ensure the success of your project

47 Degrees can work with you to help manage the risks of technology evolution, develop a team of top-tier engaged developers, improve productivity, lower maintenance cost, increase hardware utilization, and improve product quality; all while using the best technologies.