Android, Flash, Flex, and PHP

Portfolio Site and Blog

Android, Flash, Flex, and PHP header image 2

Styling Android With Defaults

January 8th, 2012 · 6 Comments · Android, OOP, Styling

According to Android’s own documentation, there is no documentation for styling Android. You’d think with the power of Google and huge market penetration, the Android team with have the commitment by now to document their code and features, but that’s another story. So what does Android officially say about styling? “Go read the source code.” Well, that’s a terrible stance and it leaves a developer guessing for hours, days, and even weeks. The things I’m going to share in this post took me quite a while to learn and I wish someone showed me early on. They will speed up the process and allow your styling to be more flexible to change. The rest of this article will talk about setting up a default theme to globally style your application.

Disclaimer:
If you’re not already quite familiar with styling Android this post is not for you. Seriously, don’t read it, you’ll just end up hating me. Keeping true to this blog, below I’m going to talk about an approach not a walk through of how  and what. If this is you, now would be a good time to read what documentation there is on styling Android and come back and read this after you have a basic understanding of styles and themes.

It wasn’t until I released several applications that I learned how to style Android properly. I say properly because I was indeed styling my applications but I wasn’t styling them in a flexible manner that would easily accommodate change. I was applying the style tag to each and every widget that needed styled.  When a style changed or I needed something different, I had to go back through each element and reapply a new style tag to it. Think about all the widgets/view there are in an application. Now think about going through each one and applying a style tag. Yuck, this took a lot of time and I would miss widgets here and there. This approach I was taking to styling Android was very rigid, brittle and I was repeating myself. As an OO developer this bugged me. I wasn’t creating my own theme, I was using Android’s theme of Dark or Light and styling each widget as needed. This is and was not good.

So let’s take a look at the screenshot of the styled app below and download the source code.

Now obviously from the screenshot, you love this app and want to make one just like it. Cool. I’m going to explain the 2 important concepts right now that took me forever to learn. Let’s check out the code-screenshot below to get started.

Let talk about the red arrows first. An Android Theme has references to styles that define the default skin/style for each Widget. What do I mean by that? For example, look at line 19 in the screenshot: <item name=”android:buttonStyle”>@style/Button</item>. This tells our app that all buttons will have the default style as defined by our style “Button.” This means you don’t have to go through each and every button and apply the style tag. It comes with this default skin. Awesome, right? Yuppers, and this is available for each widget in Android. You can see right below that we do the same for our ListView giving the dividers a default height of 5dp and a blueish color. And you can keep doing this for each widget you want to custom style until your heart’s content. Besides rapidly speeding up the process for styling an Android application this approach also creates consistency in your application. And if you think about it, it is the approach that Android is taking itself. That alone seems like a good reason to use this approach.

 How do I know what the widget names are called so I can style them?

Yup, this is the part where Android says there is no or lacking documentation. You really do have to read the source code, but it isn’t that bad. Let’s check out two files called themes.xml and styles.xml. Go to your Android sdk installation folder and then follow this path: {Android}/sdk/platforms/android-8/data/res/values. In here you will see a file called themes.xml. Go ahead and open it and look at the tag that says <style name=”Theme”> or check out the code below.

<style name="Theme">
        <item name="colorForeground">@android:color/bright_foreground_dark</item>
        <item name="colorForegroundInverse">@android:color/bright_foreground_dark_inverse</item>
        <item name="colorBackground">@android:color/background_dark</item>
        <item name="colorBackgroundCacheHint">?android:attr/colorBackground</item>
        <item name="disabledAlpha">0.5</item>
        <item name="backgroundDimAmount">0.6</item>
 
        <!-- Text styles -->
        <item name="textAppearance">@android:style/TextAppearance</item>
        <item name="textAppearanceInverse">@android:style/TextAppearance.Inverse</item>
 
        <item name="textColorPrimary">@android:color/primary_text_dark</item>
        <item name="textColorSecondary">@android:color/secondary_text_dark</item>
        <item name="textColorTertiary">@android:color/tertiary_text_dark</item>
        <item name="textColorPrimaryInverse">@android:color/primary_text_light</item>
        <item name="textColorSecondaryInverse">@android:color/secondary_text_light</item>
        <item name="textColorTertiaryInverse">@android:color/tertiary_text_light</item>
        <item name="textColorPrimaryDisableOnly">@android:color/primary_text_dark_disable_only</item>
        <item name="textColorPrimaryInverseDisableOnly">@android:color/primary_text_light_disable_only</item>
        <item name="textColorPrimaryNoDisable">@android:color/primary_text_dark_nodisable</item>
        <item name="textColorSecondaryNoDisable">@android:color/secondary_text_dark_nodisable</item>
        <item name="textColorPrimaryInverseNoDisable">@android:color/primary_text_light_nodisable</item>
        <item name="textColorSecondaryInverseNoDisable">@android:color/secondary_text_light_nodisable</item>
        <item name="textColorHint">@android:color/hint_foreground_dark</item>
        <item name="textColorHintInverse">@android:color/hint_foreground_light</item>
        <item name="textColorSearchUrl">@android:color/search_url_text</item>
 
        <item name="textAppearanceLarge">@android:style/TextAppearance.Large</item>
        <item name="textAppearanceMedium">@android:style/TextAppearance.Medium</item>
        <item name="textAppearanceSmall">@android:style/TextAppearance.Small</item>
        <item name="textAppearanceLargeInverse">@android:style/TextAppearance.Large.Inverse</item>
        <item name="textAppearanceMediumInverse">@android:style/TextAppearance.Medium.Inverse</item>
        <item name="textAppearanceSmallInverse">@android:style/TextAppearance.Small.Inverse</item>
        <item name="textAppearanceSearchResultTitle">@android:style/TextAppearance.SearchResult.Title</item>
        <item name="textAppearanceSearchResultSubtitle">@android:style/TextAppearance.SearchResult.Subtitle</item>
 
        <item name="textAppearanceButton">@android:style/TextAppearance.Widget.Button</item>
 
        <item name="candidatesTextStyleSpans">@android:string/candidates_style</item>
 
        <item name="textCheckMark">@android:drawable/indicator_check_mark_dark</item>
        <item name="textCheckMarkInverse">@android:drawable/indicator_check_mark_light</item>
 
        <!-- Button styles -->
        <item name="buttonStyle">@android:style/Widget.Button</item>
 
        <item name="buttonStyleSmall">@android:style/Widget.Button.Small</item>
        <item name="buttonStyleInset">@android:style/Widget.Button.Inset</item>
 
        <item name="buttonStyleToggle">@android:style/Widget.Button.Toggle</item>
 
        <!-- List attributes -->
        <item name="listPreferredItemHeight">64dip</item>
        <!-- @hide -->
        <item name="searchResultListItemHeight">58dip</item>
        <item name="listDivider">@drawable/divider_horizontal_dark</item>
        <item name="listSeparatorTextViewStyle">@android:style/Widget.TextView.ListSeparator</item>   
 
        <item name="listChoiceIndicatorSingle">@android:drawable/btn_radio</item>
        <item name="listChoiceIndicatorMultiple">@android:drawable/btn_check</item>    
 
        <item name="expandableListPreferredItemPaddingLeft">40dip</item>
        <item name="expandableListPreferredChildPaddingLeft">
                ?android:attr/expandableListPreferredItemPaddingLeft</item>
 
        <item name="expandableListPreferredItemIndicatorLeft">3dip</item>
        <item name="expandableListPreferredItemIndicatorRight">33dip</item>
        <item name="expandableListPreferredChildIndicatorLeft">
                ?android:attr/expandableListPreferredItemIndicatorLeft</item>
        <item name="expandableListPreferredChildIndicatorRight">
                ?android:attr/expandableListPreferredItemIndicatorRight</item>
 
        <!-- Gallery attributes -->
        <item name="galleryItemBackground">@android:drawable/gallery_item_background</item>
 
        <!-- Window attributes -->
        <item name="windowBackground">@android:drawable/screen_background_dark</item>
        <item name="windowFrame">@null</item>
        <item name="windowNoTitle">false</item>
        <item name="windowFullscreen">false</item>
        <item name="windowIsFloating">false</item>
        <item name="windowContentOverlay">@android:drawable/title_bar_shadow</item>
        <item name="windowShowWallpaper">false</item>
        <item name="windowTitleStyle">@android:style/WindowTitle</item>
        <item name="windowTitleSize">25dip</item>
        <item name="windowTitleBackgroundStyle">@android:style/WindowTitleBackground</item>
        <item name="android:windowAnimationStyle">@android:style/Animation.Activity</item>
        <item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
 
        <!-- Dialog attributes -->
        <item name="alertDialogStyle">@android:style/AlertDialog</item>
 
        <!-- Panel attributes -->
        <item name="panelBackground">@android:drawable/menu_background</item>
        <item name="panelFullBackground">@android:drawable/menu_background_fill_parent_width</item>
        <item name="panelColorBackground">#fff</item>
        <item name="panelColorForeground">?android:attr/textColorPrimaryInverse</item>
        <item name="panelTextAppearance">?android:attr/textAppearanceInverse</item>
 
        <!-- Scrollbar attributes -->
        <item name="scrollbarFadeDuration">250</item>
        <item name="scrollbarDefaultDelayBeforeFade">300</item>
        <item name="scrollbarSize">10dip</item>
        <item name="scrollbarThumbHorizontal">@android:drawable/scrollbar_handle_horizontal</item>
        <item name="scrollbarThumbVertical">@android:drawable/scrollbar_handle_vertical</item>
        <item name="scrollbarTrackHorizontal">@null</item>
        <item name="scrollbarTrackVertical">@null</item>
 
        <!-- Widget styles -->
        <item name="absListViewStyle">@android:style/Widget.AbsListView</item>
        <item name="autoCompleteTextViewStyle">@android:style/Widget.AutoCompleteTextView</item>        
        <item name="checkboxStyle">@android:style/Widget.CompoundButton.CheckBox</item>
        <item name="dropDownListViewStyle">@android:style/Widget.ListView.DropDown</item>
        <item name="editTextStyle">@android:style/Widget.EditText</item>
        <item name="expandableListViewStyle">@android:style/Widget.ExpandableListView</item>
        <item name="expandableListViewWhiteStyle">@android:style/Widget.ExpandableListView.White</item>
        <item name="galleryStyle">@android:style/Widget.Gallery</item>
        <item name="gestureOverlayViewStyle">@android:style/Widget.GestureOverlayView</item>
        <item name="gridViewStyle">@android:style/Widget.GridView</item>
        <item name="imageButtonStyle">@android:style/Widget.ImageButton</item>
        <item name="imageWellStyle">@android:style/Widget.ImageWell</item>
        <item name="listViewStyle">@android:style/Widget.ListView</item>
        <item name="listViewWhiteStyle">@android:style/Widget.ListView.White</item>
        <item name="popupWindowStyle">@android:style/Widget.PopupWindow</item>
        <item name="progressBarStyle">@android:style/Widget.ProgressBar</item>
        <item name="progressBarStyleHorizontal">@android:style/Widget.ProgressBar.Horizontal</item>
        <item name="progressBarStyleSmall">@android:style/Widget.ProgressBar.Small</item>
        <item name="progressBarStyleSmallTitle">@android:style/Widget.ProgressBar.Small.Title</item>
        <item name="progressBarStyleLarge">@android:style/Widget.ProgressBar.Large</item>
        <item name="progressBarStyleInverse">@android:style/Widget.ProgressBar.Inverse</item>
        <item name="progressBarStyleSmallInverse">@android:style/Widget.ProgressBar.Small.Inverse</item>
        <item name="progressBarStyleLargeInverse">@android:style/Widget.ProgressBar.Large.Inverse</item>
        <item name="seekBarStyle">@android:style/Widget.SeekBar</item>
        <item name="ratingBarStyle">@android:style/Widget.RatingBar</item>
        <item name="ratingBarStyleIndicator">@android:style/Widget.RatingBar.Indicator</item>
        <item name="ratingBarStyleSmall">@android:style/Widget.RatingBar.Small</item>
        <item name="radioButtonStyle">@android:style/Widget.CompoundButton.RadioButton</item>
        <item name="scrollViewStyle">@android:style/Widget.ScrollView</item>
        <item name="horizontalScrollViewStyle">@android:style/Widget.HorizontalScrollView</item>
        <item name="spinnerStyle">@android:style/Widget.Spinner</item>
        <item name="starStyle">@android:style/Widget.CompoundButton.Star</item>
        <item name="tabWidgetStyle">@android:style/Widget.TabWidget</item>
        <item name="textViewStyle">@android:style/Widget.TextView</item>
        <item name="webTextViewStyle">@android:style/Widget.WebTextView</item>
        <item name="webViewStyle">@android:style/Widget.WebView</item>
        <item name="dropDownItemStyle">@android:style/Widget.DropDownItem</item>
        <item name="spinnerDropDownItemStyle">@android:style/Widget.DropDownItem.Spinner</item>
        <item name="spinnerItemStyle">@android:style/Widget.TextView.SpinnerItem</item>
        <item name="dropDownHintAppearance">@android:style/TextAppearance.Widget.DropDownHint</item>
        <item name="keyboardViewStyle">@android:style/Widget.KeyboardView</item>
        <item name="quickContactBadgeStyleWindowSmall">@android:style/Widget.QuickContactBadge.WindowSmall</item>
        <item name="quickContactBadgeStyleWindowMedium">@android:style/Widget.QuickContactBadge.WindowMedium</item>
        <item name="quickContactBadgeStyleWindowLarge">@android:style/Widget.QuickContactBadge.WindowLarge</item>
        <item name="quickContactBadgeStyleSmallWindowSmall">@android:style/Widget.QuickContactBadgeSmall.WindowSmall</item>
        <item name="quickContactBadgeStyleSmallWindowMedium">@android:style/Widget.QuickContactBadgeSmall.WindowMedium</item>
        <item name="quickContactBadgeStyleSmallWindowLarge">@android:style/Widget.QuickContactBadgeSmall.WindowLarge</item>
 
        <!-- Preference styles -->
        <item name="preferenceScreenStyle">@android:style/Preference.PreferenceScreen</item>
        <item name="preferenceCategoryStyle">@android:style/Preference.Category</item>
        <item name="preferenceStyle">@android:style/Preference</item>
        <item name="preferenceInformationStyle">@android:style/Preference.Information</item>
        <item name="checkBoxPreferenceStyle">@android:style/Preference.CheckBoxPreference</item>
        <item name="yesNoPreferenceStyle">@android:style/Preference.DialogPreference.YesNoPreference</item>
        <item name="dialogPreferenceStyle">@android:style/Preference.DialogPreference</item>
        <item name="editTextPreferenceStyle">@android:style/Preference.DialogPreference.EditTextPreference</item>
        <item name="ringtonePreferenceStyle">@android:style/Preference.RingtonePreference</item>
        <item name="preferenceLayoutChild">@android:layout/preference_child</item>
 
        <!-- Search widget styles -->
        <item name="searchWidgetCorpusItemBackground">@android:color/search_widget_corpus_item_background</item>
    </style>

This is the default style of an Android application. And this is how each widget has a default style applied to it. More importantly, look at all those items you can style yourself! To change any of them, all you have to do is set the appropriate attribute to reference your own custom style and then that widget is globally styled in your application. Let’s look at one of the Android’s defaults, textViewStyle, which is what gives the default appearance to the TextViews. Here you can see that the textViewStyle attribute points to an Android style of Widget.TextView located in the styles.xml file. Open it, and you’ll see this

<style name="Widget.TextView">
   <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
</style>

This is how Android styles itself to have defaults for each widget. Pretty cool, eh?

So how about them blue arrows in that diagram above? I like blue and you haven’t even talked about them at all yet.

Those are references to attributes in the theme. Check out line 33 that has the blue arrow, the textColor property on TextApperance.Large. You can see that the textColor value is a reference to the color value held in the Theme’s textColorTerinary attribute that we’ve set ourselves. And here was my stumbling block for a while: even though the syntax has the android namespace on it of ?android:attr/textColorTertiary, it’s not a reference to the original Android’s Theme attribute value, but the one we just defined! This is very handy. For instance, we don’t have to define our own style for Android’s TextView because its textAppearance property has a reference to the textAppearanceSmall property of the Theme. And since we just defined our own value for that all the TextViews now take on our new style. Woot woot!

 So what does all this mean and what is the meaning life, the universe, everything?

42 and this is general approach you should be taking to style your apps on Android. Don’t go through and add the style=”@style/FooBar” to each and every ListView or Button or TextView like I once did and I see a lot of other developers doing. Define a default style for them in your application’s theme, set it in your Manifest file, and then custom style each Widget as needed. This is the approach Android uses natively and so should you.

Sources:
Click here to download the example files

Edit: Screenshot for @Norfeldt to show how to set the theme in the Eclipse Graphical Layout view.

 

Tags: ·····

6 responses so far ↓

  • 1 Brian Williammee // Jan 9, 2012 at 4:25 am

    “Don’t go through and add the style=”@style/FooBar” to each and every ListView or Button or TextView.”

    Been there / done that. It’s not fun. Thanks for this. I’ve got you bookmarked and will make use of this on my next project.

  • 2 musselwhizzle // Jan 9, 2012 at 4:35 am

    @Brian, Thanks for the nice comment. I thought this was a nice feature not talked much about in the community and wanted to get the info out the community. Glad you enjoyed it. Cheers.

  • 3 Norfeldt // Jan 21, 2012 at 4:40 pm

    Thank you so MUCH!!! I still need to practice it a lot since these stylesheet don’t do autocomplete or suggestions, but I know I will find it handy since most of my coding time goes to the UI.

  • 4 Norfeldt // Jan 22, 2012 at 12:34 pm

    A very basic question: How do I view my theme in the WYSIWYG Eclipse graphical layout editor so I don’t have to compile and run the app all the time to see the result.
    I can only choose the basic android themes and not the one I have created.
    http://dl.dropbox.com/u/3216968/styling%20android.png

  • 5 musselwhizzle // Jan 22, 2012 at 3:37 pm

    @Norfeldt, Hi buddy, I added a screenshot at the end of the post. I’m not sure why your theme isn’t showing in the list, but you can see in my screenshot attached the theme shows up and I just select it.

  • 6 Norfeldt // Jan 24, 2012 at 8:29 am

    I just updated the ADT in eclipse and the new version seems to support own custom themes. Thanks a lot!

Leave a Comment


× six = 42