
Best practices for happy Android resources
Architectural discussions for Android are all the rage but people seem to ignore the unsung hero that is the Android resource system. Treat it with love and it will fill your life with rainbows — ignore it and you’re in for a bunch of tech and design debt that’ll make your app sad, old and squeaky. This is a list of suggestions that will help keep that beast tamed and your codebase sparkling clean 🏆
Themes and Styles
- All styles should have a parent. This is to help with cases where you need to use a style in a theme attribute. Then you can safely use it as the default style for all widgets of a type in a Theme (e.g.
?android:textViewStyle) without losing the sane defaults Android provides. - Prefer inheriting from AppCompat instead of system styles to ensure backwards compatibility.
- Do not create styles that are only used once.
- Do not create styles for groups of attributes that just happen to be the same. (e.g.
16dpleft padding). - Follow naming conventions of your style’s parent. By matching system/AppCompat names they’ll be easier to find (e.g.
<style name=”Widget.Shazam.Button” parent=”@style/Widget.AppCompat.Button”/>) - <opinion_alert>Use implicit inheritance when possible. It’s slightly easier to navigate and forces you to name and structure styles better. </opinion_alert>
- Group widget styles based on the widget they’re designed for. Again, way easier to find.
- Do not define
layout_*attributes in styles. These are layout specific and should be duplicated for each layout even if they happen to be the same. - On that same point, using dimensions for duplicated
layout_*attributes should be enough to ensure views behave the same without risking values being ignored because of the inflation method used. - Qualified resources are your friend. Instead of defining multiple styles that have hardcoded dimensions/drawables and are switched based on configuration, only specify one style and define resource variables that point to a different resource for each configuration. This way your large style library is kept as concise (and navigable) as possible.
Text appearance
- TextAppearance is not a normal Widget Style. TextAppearance only controls:
textColor,textColorHighlight,textColorHint,textColorLinktextSizetextStyletextAllCapstypefacefontFamily- Shadow (
shadowColor,shadowDx,shadowDy,shadowRadius) elegantTextHeightletterSpacingfontFeatureSettings
- Attributes set using
styleoverride ones set usingtextAppearance. Attributes set in the layout override everything. - Define a TextAppearance library (even if it’s only a direct subset of the ones provided by AppCompat) and only use that in your themes and layouts. This will make future app-wide and OS independent look & feel updates a 2 minute change. For extra points define it in a separate file like
styles_textappearance.xmland share it with your designers. They are sure to love you. - For even more points use themed resources for colours and string resources for your fonts. Don’t forget the
.Inversevariants! - To ensure consistent-looking TextViews, do not define any of the TextAppearance attributes in a normal style, but always set a TextAppearance from your library on that style’s
android:textAppearancefield.
Colours
- Keep naming consistent. Colours with transparency are named:
<solid_colour_name>_XXpc, where XX is the alpha value expressed as a %. For example,black_60pcis#80000000. - Keeping colours grouped obviously helps too. A good way to group them is keeping the following separate as they tend to be large enough groups on their own: greys, white variants, black variants, all brand palette colours, and then all references to these, grouped by feature. This way the actual colour definitions will rarely be changed, and your layouts and styles needn’t be touched if they do. YMMV, so decide based on your colour list.
- If trying to override a colour in another configuration, use
refs.xml. An example of this could be switching the status bar colour based on API level from one grayscale value to another.colors.xmlshould not know about details like that, it’s only a library. - This colour list could also be shared with your design team so they don’t flood you with new colours for every new screen, and old screens are kept up to date, keeping both the app and your xml lean and consistent.
Attributes (attrs.xml)
- Attribute names should use
camelCaseto keep consistent with the system. - If a system attribute fits your needs, use that instead of creating a new one. Examples are background, foreground, color etc. You can even include them in
<declare-styleable>tags and layouts without re-defining them. Just useandroid:before the name — no need to specify format. This way everyone knows what values are expected and how the view will be affected.
Resources
- Drawable names should look like:
<type>_<group>_<subgroup>(_<variant>).xml - E.g.
bg_button_primary.xmlfor a primary-color button background. - Common drawable prefixes:
ic_(icons),bg_(backgrounds),div_(dividers). - Same for layouts:
activity_,fragment_,view_anditem_are common prefixes.
General notes
- Margin is a layout attribute and controls the space around the view the parent leaves empty. Padding is a view attribute and controls internal space left empty within the view. They are almost never interchangeable and if unsure, use margin. Margin should be used for positioning, whereas padding should be used for internal concerns of a
Viewlike touch feedback and increasing the clickable area. - For buttons, use styles instead of just backgrounds. This way, you should get more stuff for free (e.g.
android:stateListAnimator) and therefore better UI and UX. - XML can get very unreadable very fast. As you would in Java, always try to group attributes/styles/themes together based on their type and look.
Following these guidelines at Shazam has made creating polished and consistent layouts a breeze. Having structured our resources this way helped immensely in our redesign efforts, as neatly separated resources make finding, moving, modifying and deleting them much easier.
We’d love to hear your thoughts or tips you’re using in your own apps, so please share them in the comments!
