The Android Style and Theme system can be daunting to approach and this post is meant to be a gentle introduction to the theme system. It is also intended to help you define custom themes for use with the Janrain Engage Social Login for Android SDK.
The style and theme system is complex and powerful. It is used to skin the appearance of Android applications. It provides the default values for the attributes of each View on the screen. These attributes define the bulk of the pixel by pixel appearance of the screen. The remainder is provided by the Android layout system. This post assumes familiarity with the layout system, e.g. the XML files which define View hierarchies.
To get started with themes, it is easiest to begin by extending an existing theme that is similar to your desired appearance. Then you can tweak individual attributes, but let the parent theme take care of attributes out of scope of your customization. Commonly used base themes include the Holo theme, introduced with Honeycomb, and the original Android theme, Theme. Both Holo and Theme come in light and dark variants.
Creating a Custom Android Theme
To implement a custom theme create or edit MyAndroidApp/res/values/themes.xml and add the following:
<resources> ... <style name="MyCustomTheme" parent="android:style/Theme"> <item name="android:textColorPrimary">#ffff0000</item> </style> ... </resources>
In your AndroidManifest.xml apply the theme to the activities you want to style:
<activity android:name="com.myapp.MyActivity" ... android:theme="@style/MyCustomTheme" />
Your new theme will be applied to your activity, and text is now bright red.
Choosing a Theme to Extend
Android themes are rich mediums, and there are many attributes defined that affect the style of the user interface. Many of those attributes must be defined for proper operation. Because there are so many attributes, and many attributes must be defined for proper operation, it is best to extend an existing theme.
The parent attribute of the <style> element controls which theme your custom theme will extend. There are four base Android themes and two Janrain themes that are excellent candidates for extension:
- Theme: This is the base Android theme introduced with the first version of Android. It is a dark theme with light text and works on all versions of Android. It may vary from device to device according to manufacturer or carrier alterations (such as HTC Sense)
- Theme.Light: This is a light variation of Theme. It displays dark text on a light background
- Theme.Holo: This was the new Android theme introduced with Honeycomb. It features more “modern” styling, and it is only available on Android versions 3.0 and above. Theme.Holo cannot be altered by the device manufacturer or carrier. It can still be extended by application themes, however
- Theme.Holo.Light: This is a light variation of Theme.Holo
There are also two themes bundled with the Janrain Engage for Android library which adapt between Theme and Theme.Holo depending on the running version of Android:
- Theme.Janrain:This is a dark theme that selects between Theme and Theme.Holo depending upon the running version of Android
- Theme.Janrain.Light: This is a light variation of Theme.Janrain
Be aware that the Holo theme is not available on Android versions 2.3 and below. If you wish to customize the Holo theme and simultaneously support these lesser versions of Android, you will need to use the theme selector technique to use the appropriate theme one each version of the platform.
Therefore, if you would like to use Theme.Holo theme where available, and fall back to Theme elsewhere then you should extend Theme.Janrain.
Defining Color Drawable Resources
If you wish to present the Janrain Engage user interface themed with your application’s color, first define your color as an Android resource. To define a custom color, create or edit MyAndroidApp/res/values/colors.xml and add the following:
<resources> ... <color name="my_custom_color">#ff1a557c</color> ... </resources>
Note: If your custom color has a dark value then you may wish to have your custom theme extend Theme instead of Theme.Light.
Applying Colors to Theme Attributes
Your color resource can then be applied to some theme attributes, such as the window background and the primary text color, by adding <item> elements to your custom theme. These attributes are defined in your styles.xml file. For example, to apply the custom color to the window background, add the following two <item> elements to your custom theme, defined in MyAndroidApp/res/values/styles.xml file:
<resources> ... <style name="MyCustomTheme" ...> <item name="android:windowBackground">@color/my_custom_color</item> <item name="android:colorBackgroundCacheHint">@color/my_custom_color</item> </style> ... </resources>
The first <item> controls the background Drawable of the window (a color is a type of Drawable.) The second <item> sets the cache color hint, used by the provider list screen in the library, and other instances of ListView. The windowBackground attribute also accepts Android Drawable values. Drawables include XML defined gradients, XML defined colors, and images. If you use a non-solid-color Drawable for a background you must set android:colorBackgroundCacheHint to #00000000.
Applying Custom Themes to the Janrain Engage for Android User Interface
Finally, to apply your custom theme with your custom background color to the library user interface, edit your AndroidManifest.xml and change the android:theme attribute of the activity definition that has the attribute android:name=”com.janrain.android.engage.ui.JRFragmentHostActivity$Fullscreen”:
<activity android:name="com.janrain.android.engage.ui.JRFragmentHostActivity$Fullscreen" android:configChanges="orientation|screenSize" android:theme="@style/MyCustomTheme" android:windowSoftInputMode="adjustResize|stateHidden" />
For proper operation of the library on Android tablets you will also need to provide a dialog variant of your theme. The dialog variant should extend an existing dialog theme. For example:
<resources> ... <style name="MyCustomThemeDialogVariant" parent="android:Theme.Janrain.Dialog"> <item name="android:windowBackground"<@color/my_custom_color</item> <item name="android:colorBackgroundCacheHint">?android:windowBackground</item> </style> ... </resources>
The dialog variant should be applied to the activity element of your Android manifest with the attribute android:name=”com.janrain.android.engage.ui.JRFragmentHostActivity”:
<activity android:name="com.janrain.android.engage.ui.JRFragmentHostActivity" android:configChanges="orientation|screenSize" android:theme="@style/MyCustomThemeDialogVariant" android:windowSoftInputMode="adjustResize|stateHidden" />
Using a Custom Nine-Patch With Buttons
A nine-patch drawable is a special kind of image which can be scaled in width and height while maintaining its visual integrity. Nine-patches are the most common way to specify the appearance of Android buttons, though any drawable type can be used.
Example nine-patch PNG.
Notice the one pixel black lines around the edge, they control the scaling of the image.
- Save this bitmap as MyApplication/res/drawable/my_nine_patch.9.png
- Define a new style (you can define the new style in the same file that you defined your custom theme from Creating a Custom Android Theme above) …:
<resources> ... <style name="MyCustomButton" parent="android:Widget.Button"> <item name="android:background">@drawable/my_nine_patch</item> </style> ... </resources>
- Apply the new button style to the buttonStyle attribute of your custom theme:
<resources> ... <style name="MyCustomTheme" parent=...> ... <item name="android:buttonStyle">@style/MyCustomButton</item> </style> ... </resources>
Now the buttons in the activities your theme is applied to have custom images. However, you may notice that they don’t change appearance when selected. Read Selector Drawables below for an introduction to using multiple drawables to define one drawable that changes based on state.
Other Kinds of Drawables
Drawables are the Android resources used to define the pixels drawn to the screen. (And Android layout resources define what drawables are drawn where.) There are many different kinds of drawable resources.
A selector is a drawable which changes based on state. Here is an example selector which switches between the example.9.png nine-patch described above when unselected and your custom color defined above in Defining Color Drawable Resources. For example, create MyApplication/res/drawable/my_custom_selector.xml and add the following:
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@color/my_custom_color" android:state_pressed="true"/> <item android:drawable="@drawable/example"/> </selector>
Now you can use this selector as the drawable applied to the buttonStyle attribute in your custom theme and buttons will change appearance based on their state:
<resources> ... <item name="android:background">@drawable/my_custom_selector</item> </style> ... </resources>
Solid flood fill is not the right appearance for selected buttons in your application. You could copy your custom nine-patch and apply a visual affordance for the pressed state and use the altered nine-patch for the pressed state.
Gradients are a great way to polish the appearance of an application and they are very easy to define and use in an Android theme. For example, create MyApplication/res/drawable/my_gradient.xml and add the following:
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <gradient android:angle="270" android:startColor="#1a557c" android:endColor="#62c4e9" /> </shape>
Then, apply the gradient to the windowBackground attribute of your custom theme:
<resources> ... <style name="MyCustomTheme" parent=...> ... <item name="android:windowBackground">@drawable/my_gradient</item> <item name="android:colorBackgroundCacheHint">#00000000</item> </style> ... </resources>
Note: Because you are using a gradient as the background you must set the cache color hint to #00000000 for the proper operation of ListView.
Themes offer a wide variety of attributes with which you can control the appearance of an Android activities user interface. For more information see the Android Styles and Themes guide, the Android theme.xml source, and the Android attrs.xml source. Here is a short list of commonly used and otherwise useful Theme attributes you may wish to specify:
(From the Android platform data/res/valus/attrs.xml)
This is a hint for a solid color that can be used for caching rendered views. This should be the color of the background when there is a solid background color; it should be null when the background is a texture or translucent. When a device is able to use accelerated drawing (thus setting state_accelerated), the cache hint is ignored and always assumed to be transparent.
Default appearance of text: color, typeface, size, and style.
The most prominent text color.
Text color, typeface, size, and style for “large” text. Defaults to primary text color.
Text color, typeface, size, and style for “medium” text. Defaults to primary text color.
Text color, typeface, size, and style for “small” text. Defaults to secondary text color.
Normal Button style.
The drawable for the list divider.
Drawable to use as the overall window background. As of Honeycomb, this may be a selector that uses state_accelerated to pick a non-solid color when running on devices that can draw such a bitmap with complex compositing on top at 60fps.
There are a few special considerations to use when setting this drawable:
- This information will be used to infer the pixel format for your window’s surface. If the drawable has any non-opaque pixels, your window will be translucent (32 bpp).
- If you want to draw the entire background yourself, you should set this drawable to some solid color that closely matches that background (so the system’s preview of your window will match), and then in code manually set your window’s background to null so it will not be drawn.
Drawable to use as a frame around the window.
Flag indicating whether this window should have an Action Bar in place of the usual title bar.
Theme to use for alert dialogs spawned from this theme
Default ProgressBar style. This is a medium circular progress bar.
Reference to a style for the Action Bar.