Cdacians

Cdacians
Cdacians

Thursday, 7 September 2017

Android resources and attributes cheatsheet

Android resources and attributes cheatsheet

Few days ago I stumbled upon one of my early-Android-dev-days cheatsheet I created for understanding different syntax when dealing with Android resources and theme attributes.
Surprisingly, I found it quite useful now, so I decided to make it more blogpost-ready and share with others.
Just so you understand what I will be talking about today, consider following ways to set view's background color via xml layout:
android:background="@color/colorPrimary"  
android:background="@com.myapp:color/colorPrimary"  
android:background="?colorPrimary"  
android:background="?attr/colorPrimary"  
android:background="?com.myapp:attr/colorPrimary"  
android:background="?com.myapp:colorPrimary"  
android:background="?android:colorPrimary"  
android:background="?android:attr/colorPrimary"  
Exciting, isn't it? Well, I hope I'll try to break it down, so it doesn't look this scary anymore.

Referencing resources vs style attributes

This is a small detour into Android basics since it is really important to understand the difference between @ and ? before we move any further.
When we use @ - we reference actual resource value (color, string, dimension, etc). I.e. this resource should have an actual value. In this case we know exactly what value we are dealing with.
I.e.
app/src/main/res/values/color.xml
<?xml version="1.0" encoding="utf-8"?>  
<resources>  
    <color name="colorPrimary">#3F51B5</color>
</resources>  
So when we try to reference this value in xml (android:background="@color/colorPrimary"), background will be set to color #3F51B5no matter what theme is currently set for this activity.
On the other side, when you see ? notation - it means that we are trying to reference a style attribute - a value which may vary depending on current theme. I.e. in each specific theme I can override this attribute, so I don't need to change my XML layout - I just need to apply proper theme:
<resources>  
    <style name="AppTheme" parent="Theme.AppCompat.Light">
        <item name="colorPrimary">#F00</item>
    </style>
</resources>  
<TextView  
    android:id="@+id/my_text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="?colorPrimary"/>
In this case, we ask Android: "Hey, give me a value of colorPrimary attribute which is specified in current theme". In this case it is a bit harder to tell exactly what color our background is going to be since it really depends on theme applied to the activity this layout belongs to.

Syntax

Now let's see what is the actual syntax for referencing different resources.

Referencing resources (@)

@[package_name:]resource_type/resource_name
  • package_name - optional name of the package this resource belongs to (by default - your app package). Reserved package - android. Used for resources shipping with platform
  • resource_type - the R subclass for the resource type (attrcolorstringdimen, etc)
  • resource_name - an actual name of the resource we are trying to reference.
Let's actually take my first 2 examples and try to break them down:
android:background="@color/colorPrimary"  
android:background="@com.myapp:color/colorPrimary"  
As you can see - both of them are equivalent since by default, package name is set to our app's package name, so it is not necessary to mention it:
  • package(optional) = com.myapp
  • resource_type = color
  • resource_name = colorPrimary
As you might think, Android ships with some predefined resources for entire OS. F.i. I could reference some built-in color this way:
android:background="@android:color/holo_orange_dark"  
Here is what we got in this case:
  • package = android - referencing built-in resources
  • resource_type = color
  • resource_name = holo_orange_dark
PLEASE NOTE
Nowadays, lots of people use AppCompat (and if you don't - you probably should), and AppCompat often defines its own resources. Even though AppCompat is a first-party lib shipped by Google, it is not really a part of operating system. Instead, those resources get merged into your app, so you don't need to use android keyword to reference those.
Example:
android:background="?selectableItemBackground"  
Here, even though we don't have custom style attribute name selectableItemBackground in our app (notice that we didn't use android: prefix), we can still reference it because it was "added" to our app by AppCompat.

Referencing style attributes (?)

Guess what. The syntax is pretty similar to resources:
?[package_name:][resource_type/]resource_name
There one small difference though.
The only allowed resource_type when referencing style attributes is attr. So given that, Android packaging tool actually allows us to omit resource_type, so it is effectively optional.
So following expressions mean exactly the same thing from Android perspective:
android:background="?com.myapp:attr/colorPrimary" //verbose format  
android:background="?com.myapp:colorPrimary" //attr is skipped since its optional  
android:background="?attr/colorPrimary" //package is skipped since its optional  
android:background="?colorPrimary"  // package & attr is skipped  
As you can see, syntax is super simple after all. Never get confused again!

No comments:

Post a Comment