Background

When creating custom view, you most likely want to use custom attributes for easy customization. To do that, you’ll typically declare your custom attributes with <declare-styleable /> in an attrs.xml file under the project’s res/values/ folder. It will then be parsed at compilation by aapt into R.styleable.MyCustomView and the corresponding R.styleable.MyCustomView_attr1, R.styleable.MyCustomView_attr2 and so forth for each of the attributes in the styleable.

There are cases, however, in particular when you’re only using predefined attributes such as those defined in android.R.attr.* or appcompat’s R.attr.*, you may want or need to declare styleable programmatically instead of depending on xml resources. One reason can be if you want or need to distribute your custom view as a JAR only distribution. Another reason is when your custom view extends other view, and you need to get the values of attributes defined by the base class but don’t have accessor method for the attribute, e.g. the android:src of ImageView, android:textAppearance of the TextView, and many others. Or you might want to do it purely just for convenience.

How To Do It

Here’s how you can programmatically declare styleable and use it to customize your component:

What Is Styleable

A styleable is basically an int[] containing a set of attributes. You use this attributes to obtain values you need to customize the behavior or appearance of your component. When you call the Context#obtainStyledAttributes() method, you’ll get back a TypedArray object containing the values referenced by the attributes, taking into consideration the default values from the style and theme set in your app. In order to get the value referenced by particular attribute, you call an appropriate method of the TypedArray with the attribute’s index (not value!) as parameter.

How This Works

For optimization reasons, the context.obtainStyledAttributes() method, which internally calls Resources#obtainStyledAttributes(), and which in turn calls a native method to fill the requested values, assumes that the styleable is sorted in ascending order. So for this to work, it is important to sort your styleable before calling the context.obtainStyledAttributes() method. It can be done simply by calling Arrays.sort(styleable) on your styleable. If the styleable is not correctly sorted, you’ll get unexpected result. If you declare your styleable using xml <declare-styleable />, the aapt will have it sorted correctly when it compiles the resources.

Conclusion

We’ve been using this simple tips for years, but have never come across any codes that use this techniques (we’ve seen some codes with a styleable of a single attribute, though, but that doesn’t require sorting). So we thought we’d share it. Hope it helps some developers out there.

We’ve put a sample project at Github to demonstrate this tips.

Happy coding 🙂

Pin It on Pinterest

Shares
Share This