ActionBar

ActionBarCompat – Part 2

In the previous article we began converting the existing project from the Styling Android series on ActionBar to use the ActionBarCompat library. Once we had got a Gradle build working, we found that we had a lot of resource errors once we switched the compiler to compile against API 7. In this article we’ll look at resolving those errors.

The primary cause of our errors is that the styles that we use in res/styles.xml are dependent on the Holo style and attributes which were added in later versions of Android.

There are some new themes which have been included in the ActionBarCompat library named Theme.AppCompat, Theme.AppCompat.Light, and Theme.AppCompat.Light.DarkActionBar. These are roughly equivalent to their counterparts in API 11+ Theme.Holo, Theme.Holo.Light, and Theme.Holo.Light.DarkActionBar.

So we need to change all of our themes and styles which are reliant on Holo ones to use their AppCompat equivalents.

There is a direct equivalent for all of the parent styles with the exception of android:Widget.Holo.EditText. For that we’ll use Widget.EditText instead.

I haven’t listed the entire styles.xml here, but it is included in the source.

The other things that we have to do is change the namespace of some of the ActionBar specific attributes. The reason for this becomes apparent when we consider how ActionBarCompat actually works. When running on a version of the OS which supports a native ActionBar implementation, ActionBarCompat simply acts as a wrapper for the implementation baked into the OS; but when we run on 2.x which does not support ActionBar, then the backported library within the appcompat library is used instead. This is exactly as it should be – use the native library if available. However, it does cause a slight problem because of the way that resources and, more specifically, attributes are defined.

Each item that within our style corresponds to an attribute that is usually defined within res/values/attr.xml. When we access attributes which are defined within the OS, we need to prefix the attribute name with android: as the android namespace prefix denotes that these attributes are defined by the OS. If we omit the android: namespace prefix, then it is implicit that the attribute is defined within the resources of the local project.

When running on a version of the OS with native ActionBar support, the names that we must use for item names within our styles are, once again, baked into the OS, and we access these using the android namespace in our style items. For example:

However, we we are running on a 2.x device without native ActionBar support, we use the item name attributes from the appcompat library. When we include an Android library project into our project, the build merges the resources from any included Android libraries into the current project, and these are accessed through the default project namespace, and so we must omit the android: prefix:

Because of this we need to include both forms to ensure that the attribute gets set irrespective of whether the native or backported implementation is used.

It seems sensible to define 2 styles.xml files, one in res/values, and the other in res/values-v11. The former contains item names without the android: prefix, and the latter contains item names with the code>android: prefix. This is how you would tailor resources which target different OS versions, but it could result in maintainability issues because you may change one definition and not the other. If they both exist within the same file, you are more likely to remember to change both forms for the simple reason that they are both there in front of you when edit the file. There’s no right or wrong, here – it’s really just a matter of personal preference – although you should stay consistent!

Purely for ease of seeing the two versions side by side, I have included them in the same styles.xml:

Once again, I have not included the entire file here.

The next thing that we need to do is change our menu resources. In OS versions which include ActionBar support additional attributes were added to the menu resources to control how menus are displayed within the ActionBar:

Obviously these attributes are not supported on 2.x, so we have to ensure that we use the ones defined within the appcompat library. We do this by using the namespace of the local app resources, and specifying these particular attributes using that namespace prefix instead:

Fortunately there is no need to duplicate these resources as with the style items.

We need to do this for our actionmode.xml menu as well:

That’s the resources completed, although we’ll need to tweak things a little once we get the app running and have some minor issues to resolve.

In the next article we’ll turn our attention to our Java code, and make the necessary changes to that.

The source code for this article is available here.

© 2013 – 2014, Mark Allison. All rights reserved.

CC BY-NC-SA 4.0 ActionBarCompat – Part 2 by Styling Android is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. Permissions beyond the scope of this license may be available at http://blog.stylingandroid.com/license-information.

Leave a Reply

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