Get the most out of the tools
namespace and be a design-time XML Jedi
Picture this scenario: you’re designing some piece of UI in Android Studio. You have your XML editor in front of you, and you’ve pretty much jolted down the layout. You look at the Preview pane, and this is what you see:
Hmm. Thanks for nothing, man.
If you’ve ever done any even remotely serious XML layout work on Android you’ll have faced this scenario plenty of times. There’s only one way to check if your layout makes sense: run it on a device.
But that would require you to have some dummy data to show, and if you’re designing the XML now, it means you still probably don’t have any code done yet to bind data to the UI when the app runs. So you do something you should never do: you hardcode some dummy data into the layout XML.
<TextView
android:id="@+id/text_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.Title"
android:layout_margin="@dimen/main_margin"
android:text="I am a title" />
Well, at least, now you see something when you run it. And hey! It works! “Hey, let’s move on to crunching some code in, and we’ll come back here later to remove the hardcoded stuff.” — says the developer.
Fast-forward to 6 PM. It’s late, your code just barely got to the point where it runs without immediately crashing in a fireball, you’re dead tired and your brain is melting. So you commit your changes and issue a PR before running home.
Next day, get back to the office, open GitHub, and this is what you see:
Ooooooh crap.
Someone forgot to take out that hardcoded dummy data. Said data is also merrily leaking into the final APK, which is not good either.
That someone’s gonna have an ugly five minutes at the standup, today.
And that someone happens to be me. Ouch.
Don’t be a tool, use the tools
How could this have been avoided, you ask? Simple enough: by using the tools
namespace and its attributes.
This is going to be your best friend from now on:
xmlns:tools="http://schemas.android.com/tools"
Design time shenanigans
This new friend you’ve just met is a magical friend. It’s got an amazing power: it can convince Android Studio to ignore what the regular android:
attributes say, and do what its attributes tells it to instead. And the most incredible part is, tools
can also convince aapt
to ignore its own tools:
attributes, so that they don’t end up in the actual apk.
This perfectly fits our needs. We can then just add the xmlns:tools
declaration to the root node of our layout, and then modify our TextView
like this:
<TextView
android:id="@+id/text_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.Title"
android:layout_margin="@dimen/main_margin"
tools:text="I am a title" />
This can safely be committed under VCS, because it will be useful for other developers that end up working on that layout later on (including yourself — hey, future me, you’re welcome!), and because it will never leak into an APK.
You can use the tools:
attributes to override any regular android: attributes at design time (e.g., setting vivid backgrounds to better tweak view boundaries).
But that’s not all you can do with the tools namespace!
Power tools
While relatively little known, the tools
namespace is great and will come a long way in helping you be a better XML layout developer. You can find out some informations about the tools attributes on the Android Tools attributes reference, but we’re going to take the panoramic road here and see all the attributes at our disposal in more detail.
Besides design-time overrides of standard attributes, you can find a bunch of dedicated tools:
attributes in the namespace.
Not all attributes are the same
The tools attributes can be divided in two main categories. The first category contains all attributes that impact Lint analysis, while the second one contains all the other attributes, that (at the time of writing) concern the XML UI design phase, and thus the IDE.
Lint attributes
There are three Lint attributes in the tools
namespace:
tools:ignore
tools:targetApi
tools:locale
The ignore attribute
The ignore
attribute is basically the equivalent of Java’s @SuppressWarnings
annotation, as it tells Lint to suppress, or ignore, one or more warnings on the XML node it’s applied to.
So, assuming we have an ImageView
with a non-content (i.e., purely visual) drawable, that we declared like this:
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_main"
android:layout_marginTop="@dimen/margin_main"
android:scaleType="center"
android:src="@drawable/divider" />
Lint will highlight the lack of an android:contentDescription
attribute. But since we’re fine with having no content description here, we can use tools:ignore
to suppress the warning (and thus not break the CI builds, if you have strict Lint issues rules).
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_main"
android:layout_marginTop="@dimen/margin_main"
android:scaleType="center"
android:src="@drawable/divider"
tools:ignore="contentDescription" />
The targetApi attribute
This attribute does exactly the same thing that the @TargetApi
annotation does in Java, which is, telling Lint which is the minimum API version you’re going to use a resource on. It basically is a contract you’re making with Lint, that Lint could not otherwise assume.
For example, if your project was having a minSdkLevel 15
, and you were using a RippleDrawable
in some drawable folder that wasn’t explicitly marked -v21
, Lint would complain about it:
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/accent_color" />
If you are sure you’re not going to use this drawable on API 20 and lower (because you’re using a different drawable in the pre-Lollipop styles, for example), then you can use the tools:targetApi
to explicit this contract to Lint:
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:color="@color/accent_color"
tools:targetApi="LOLLIPOP" />
The locale attribute
This last Lint-targeting attribute is used to specify which locale a resource is actually for. It’s admittedly not the most useful attribute in the tools namespace, but here’s one case you might need it in.
If you’re developing an app that is only in one language, which is not English (or whose default locale, for some reason, is not English), then this attribute is great for stuff you put in your default resources folder.
For example, if you’re developing an app for, say, an Italian newspaper, that only serves content in Italian, there’s no point in having English as your base language. You just put Italian stuff in the default locale resources.
Well, in that case, you will probably want to do this in your res/values/strings.xml
:
<resources
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:locale="it">
<!-- Your strings go here -->
</resources>
This way Android Studio knows that your strings aren’t in English and the spell checker won’t complain about every single word you’ve got in there.
As far as I know, at the moment this attribute only disables spell checking on strings when the specified locale is not English.
In the next part(s) of this series…
Now that we’ve covered all the basics about the tools namespace, and we’ve seen the Lint attributes, we will move into the UI design-time attributes.
Thanks to Mark Allison for proofreading.