How do I cascade a style by theme in android

Basically, I'd like to have a single layout that I can skin differently on the theme. Many examples and entries on this site seem dance around the issue a little so I'm not entirely certain it can be done. Or I just don't get it.

Here's the concept.

Let's say my app is sports-related.. the app has a default them of 'SportTheme' I'd like users also to say they want the 'Football' or 'Baseball' theme, and on designated <TextView> elements, I'd like the text (defaults to 'Sport') to change to 'Football' or 'Baseball' given the overall theme applied to the activity?

in strings.xml

<string name="label_sport">Sport</string>
<string name="label_football">Football</string>
<string name="label_baseball">Baseball</string>

in activityA.java - The important thing here is that the theme is set for the activity (or application is fine, too).

@Override
protected void onCreate(Bundle savedInstanceState)
{
    Log.d(TAG, "onCreate");
    super.onCreate(savedInstanceState);
    this.setContentView(R.layout.layout_a);

    switch (user.ThemePreference)
    {
        case FOOTBALL_THEME:
            this.setTheme(R.style.FootballTheme);
            break;
        case BASEBALL_THEME:
            this.setTheme(R.style.BaseballTheme);
            break;
        default:
            this.setTheme(R.style.SportTheme);
            break;
    }
}

in layout_a.xml

...
<TextView
   android:id="@+id/tvSport"
   android:layout_height="wrap_content"
   android:layout_width="match_parent"
   android:text="@string/label_sport"
   android:style="@style/SportLabel"></TextView>

What do I do in themes/styles? Something like this? The important thing here is the text in the TextView. I'll be using the same textView in several different activities throughout the application.

<theme name="SportTheme" parent="android:Theme" />

<theme name="FootballTheme" parent="SportTheme">
   <item name="android:background">@color/brown</item>
</theme>

<theme name="BaseballTheme" parent="SportTheme">
   <item name="android:background">@color/green</item>
</theme>


<theme name="SportTheme.SportLabel">
   <item name="android:text">@string/label_sport</item>
</theme>

<theme name="FootballTheme.SportLabel">
   <item name="android:text">@string/label_football</item>
   <item name="android:textColor">@color/black</item>
</theme>


<theme name="BaseBallTheme.SportLabel">
   <item name="android:text">@string/label_baseball</item>
   <item name="android:textColor">@color/white</item>
</theme>

Thanks for any insight you can provide

Answers


To customize your UI with themes you need to define attributes you want to customize inside your themes and use references to these attributes in layouts (e.g. attr/backgroundColor).

There're three files in Android sources which are used for this purpose: attrs.xml, styles.xml and themes.xml. If you need some custom attributes for customization then you should declare them in attrs.xml. If you're going to use only predefined Android attributes then you don't need to create this file.

<declare-styleable name="SportTheme">
    <attr name="customAttribute" format="color" />
    <attr name="sportLabelStyle" format="reference" />
</declare-styleable>

The styles.xml file is used for defining sets of attribute values. For example you can define different style sets for each widget.

<style name="Widget.TextView.SportLabel" parent="@android:style/Widget.TextView">
    <item name="android:textColor">@android:color/white</item>
    <item name="android:textSize">20sp</item>
</style>

The themes.xml is the main file used for customizing. All themes are usually defined in this file. You can customize something in several ways. For example you can define a default value in the theme and reference it from a layout. Also you can define a reference to a style.

<style name="Theme.FootballTheme" parent="@android:style/Theme">
    <!-- define value for predefined Android attribute -->
    <item name="android:colorBackground">@android:color/white</item>
    <!-- define value for custom attribute -->
    <item name="customAttribute">@android:color/black</item>
    <!-- define reference to a style -->
    <item name="sportLabelStyle">@style/Widget.TextView.SportLabel</item>
</style>

layout.xml

<TextView
    android:background="?android:attr/colorBackground"
    android:textColor="?attr/customAttribute"
    style="?attr/sportLabelStyle" />

Notice that style is used without the android namespace. That's not a typo.

So if you want to customize your layout using themes you can create several themes and define default values for attributes and attribute sets (styles) and reference these values using

?[android:]attr/attributeName

Sounds difficult but it's not really. You can use Android resources as an example of styling.

Please ask your question if something is not clear.


I have written a blog post about Themes which may help you. There is also a series of article on Custom Controls which explains how to create a custom control which is themeable, and this provides additional information about how Android themes work.


Need Your Help

Envelop tag missing in xml object

c# .net xml web-services xml-deserialization

I have a web application where the users can upload a specific XML file, then i need to convert the XML file to a object which is expect in a webservice.

Passing variadic function template arguments to another function

c++ templates c++11 variadic-templates

I am trying to pass my pack to another function, it looks similar to what I'm seeing in tutorials, but not similar enough apparently:

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.