Going Material

Kedar Sarmalkar posted August 17, 2015

Google introduced material design in IO 2014 and finally established some strong android design guidelines. Here I’m going to describe some of things I had to do to convert the existing non-material TripAdvisor Flights screens to material design. Some of the steps were super easy and straight forward and some required a bit of troubleshooting and tweaking to get things right.

Change the target SDK

We had already done this some months back and changed the target SDK to 21, however in order to get the latest and greatest and at same time making sure things are still stable, we decided to bump to target SDK 22. As per googles documentation this is LOLLIPOP_MR1, or in other words, lollipop with extra sugar coating on the outside, and of course who does not want some extra sugar coating ??

Inherit from AppCompatActivity

We had a common base class that inherited from FragmentActivity, all we had to do is change that base class to inherit from AppCompatActivity (which in turn inherits from FragmentActivity). This is really important if you want to start using the material themes and get all the material goodness.

Old

New

Change Theme to “Theme.AppCompat.XX

The current themes are all derived from “Theme.Holo.XX“. However if you want to convert the theme to material, that needs to be changes to “Theme.AppCompat.XX“. AppCompat themes has similar naming like Holo theme has for e.g. Theme.AppCompat.Light is equivalent to Theme.Holo.Light. This is important if you are switching to AppCompatActivity, it is required that you switch to Theme.AppCompat else the app will crash and clearly indicate in crash logs that you need to inherit from “Theme.AppCompat…“.
Old Style

New Style

Toolbar

Material guidelines introduces new component called Toolbar. For people who on their past projects have tried to customize the ActionBar must know this very well, but it was not at all easy to customize it. Toolbar makes it really easy to customize it and add custom views inside it. In other words its an ActionBar on steroids. I’m sure people who have used ToolBar by now would agree to that. It also can act as action bar if you don’t want to customize it. All you need to do is

By stating  android:minHeight="?attr/actionBarSize", we define the toolbar to be the same height as our actionbar since we might not use toolbar everywhere, and this is the simplest way of defining that height.

Wait a minute why AppCompat ??

I will let Ian explain that…

Activity transition using shared elements

Material guidelines emphasizes a lot on animations and meaningful transitions.

From Google's material design guidelines:
Motion design can effectively guide the user’s attention in ways that both inform and delight. Use motion to smoothly transport users between navigational contexts, explain changes in the arrangement of elements on a screen, and reinforce element hierarchy.
ks.going in

Some of the simple transitions can be done with few simple lines of code as below

The reference to  android:transitionName="toolbar" simply gives an identifier for the transition framework to determine which view to animate to.

The catch here is that it will complain that it only works for OS 21 (LOLLIPOP) and above. This is where ActivityOptionsCompat and ActivityCompat.startActivity is super useful. This will handle all the cases and make this compatible for OS 20 and below. So the new code looks like below

What about transition when going back ?

Something missing?Looks better now...
ks.return missingks.return full

Its simple all you have to do is add this to your activity:

Again this will complain about only being compatible with version 21 onwards, How do we fix this ? You guessed it:

Ripple drawables

When you switch to Theme.AppCompat most of the things like buttons and default selectors will have ripples by default. But what it if you have some custom selectors for buttons ? Its super easy, copy your custom selector to drawable-v21 folder and wrap it around <ripple/>. As simple as that, the framework will handle remaining for you.

ks.cell selection

Alert Dialog

Always use android.support.v7.app.AlertDialog. This shows the material styled alert dialog even for older OS versions. Notice the dialog does not follow the ta_green style. This is done specifically since Air Watch is a ancillary product and the brand color for that is blue. Its very easy to customize that specifically for a particular dialog.ks.Screen Shot 2015-07-16 at 4.10.04 PM

We used the colorControlActivated and colorControlHighlight to make the edit text in the dialog to appear blue too. All other EditText in the app would have the default ta_green as highlight colors.

Then use the style in “android:theme” on the EditText in xml file.

Notice that we have customized the positive and negative button colors and changed the default background to white and text to black. Now all that is left to do is use the above theme when instantiating the AlertDialog in builder. NOTE: android.support.v7.app.AlertDialog.Builder takes in theme, the other AlertDialog does not take in a theme.

Things I had to struggle with a tiny bit

a. Action bar with v7 search view was not showing up

Had to dig through a lot of stack overflows and tried every solution possible. Couple of things we need to make sure when using that is

  1. Make sure we are using custom name space for actionViewClass and showAsAction. For example below I’m using “support:actionViewClass” and “support:showAsAction”, before it used to be “android:actionViewClass” and “android:showAsAction”.
  2. If you are using proguard then exclude, or else it is not able to set the action view as SearchView.

b. Supporting a menu item with custom layout––partially conflicts with section (a)

An item with a custom layout has the “android:actionLayout” tag set.

  1. Use the custom namespace for actionLayout, i.e. android:actionLayout –> support:actionLayout
  2. REMOVE support:actionViewClass. “Adding an Action View” states that “to declare an action view, use either the actionLayout or actionViewClass” That is an exclusive “either”. If you do not remove the actionViewClass tag, your menu item will not have any children.
  3. Keep support:showAsAction

c. SearchView for some reason refused to show the cursor.

This might have been due to the themes that I had to use, and since the action bar was dark, it was showing the cursor as dark. Maybe.. Maybe not .. but there was a easy workaround.

ks.Screen Shot 2015-07-16 at 4.50.51 PM

Notice the "android:textCursorDrawable" , its nothing but a simple rect drawable with white color and around 2 dp in width.

d. ActivityUnitTestCase doesn’t like AppCompat

After converting Activity’s to AppCompat themes, a test case that extends ActivityUnitTestCase failed with:

Although the Activity associated with the test used the AppCompat theme, following this forum’s advice (i.e. overriding ActivityUnitTestCase’s setActivity and explicitly setting the theme in there) fixed the problem. If the test case T extends TripAdvisorSimpleActivityTestCase, which extends ActivityUnitTestCase, override setActivity in T so that other Activity’s tested with ActivityUnitTestCase and that inherit from a variant of Theme.AppCompat (e.g. Theme.AppCompat.NoActionBar) behave properly.

Conclusion

I would say that over all it was very easy to convert the styles to material, took about 3-4 days to get all the things resolved and worked fantastically across multiple devices.

Disclosure: I only tested ICS and above as we don’t support android versions below that. However I’m confident that the code is fully compatible if we go back to supporting gingerbread.

Comparison

Pre-MaterialPost-Material
ks.nonmaterialks.material

One response to “Going Material”

  1. Josh says:

    Great read, especially the “something missing” and “ripple drawables”. Reminds me not to forget this transitions in my next material design effort.

Leave a Reply

Your email address will not be published. Required fields are marked *