Best way to change individual views styles in a multi Theme app


I have a ListView with a BaseAdapter that can have many different inflated views. I'm implementing tree Themes that user can choose from within the app. Everything was great until I needed to change the appearance of a row TextView in the ListView depending on the Theme user has chosen.

I have a solution where I'm on the fly testing like this:

@Override public View getView(int position, View convertView, ViewGroup parent) { int type = getItemViewType(position); ViewHolder viewHolder = null; if (convertView == null) { switch (type) { case TYPE_ACTIVE: // inflate active accounts if (theme == SettingsManager.InterfaceTheme.light) convertView = inflator.inflate(R.layout.a_login_roaster_light, null); else if (theme == SettingsManager.InterfaceTheme.dark) convertView = inflator.inflate(R.layout.a_login_roaster_dark, null); else convertView = inflator.inflate(R.layout.a_login_roaster_def, null); viewHolder = new ViewHolder(); viewHolder.text1 = (TextView) convertView.findViewById(R.id.txt_row1); viewHolder.text2 = (TextView) convertView.findViewById(R.id.txt_row2);

As you see I change the appearance by inflate a ny row layout. This is working and everything but is there a better way to do this since the layout is same only color or font size must change? I'm using the android-support-v7-appcompat.jar and have the Theme.AppCompat.Light Theme in my Application Manifest as default Theme. I made some Themes with this wondeful tool, <a href="http://jgilfelt.github.io/android-actionbarstylegenerator/" rel="nofollow">Android Action Bar Style Generator</a>

Here is the Style created with <a href="http://jgilfelt.github.io/android-actionbarstylegenerator/" rel="nofollow">Android Action Bar Style Generator</a>, I post one of tree styles since they are the same. This is the "light" version file located in res\values

<?xml version="1.0" encoding="utf-8"?> <!-- File created by the Android Action Bar Style Generator Copyright (C) 2011 The Android Open Source Project Copyright (C) 2012 readyState Software Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <resources> <style name="Theme.theapp_light" parent="@style/Theme.AppCompat.Light"> <item name="actionBarItemBackground">@drawable/selectable_background_theapp_light</item> <item name="popupMenuStyle">@style/PopupMenu.theapp_light</item> <item name="dropDownListViewStyle">@style/DropDownListView.theapp_light</item> <item name="actionBarTabStyle">@style/ActionBarTabStyle.theapp_light</item> <item name="actionDropDownStyle">@style/DropDownNav.theapp_light</item> <item name="actionBarStyle">@style/ActionBar.Solid.theapp_light</item> <item name="actionModeBackground">@drawable/cab_background_top_theapp_light</item> <item name="actionModeSplitBackground">@drawable/cab_background_bottom_theapp_light</item> <item name="actionModeCloseButtonStyle">@style/ActionButton.CloseMode.theapp_light</item> </style> <style name="ActionBar.Solid.theapp_light" parent="@style/Widget.AppCompat.Light.ActionBar.Solid"> <item name="background">@drawable/ab_solid_theapp_light</item> <item name="backgroundStacked">@drawable/ab_stacked_solid_theapp_light</item> <item name="backgroundSplit">@drawable/ab_bottom_solid_theapp_light</item> <item name="progressBarStyle">@style/ProgressBar.theapp_light</item> </style> <style name="ActionBar.Transparent.theapp_light" parent="@style/Widget.AppCompat.Light.ActionBar"> <item name="background">@drawable/ab_transparent_theapp_light</item> <item name="progressBarStyle">@style/ProgressBar.theapp_light</item> </style> <style name="PopupMenu.theapp_light" parent="@style/Widget.AppCompat.Light.PopupMenu"> <item name="android:popupBackground">@drawable/menu_dropdown_panel_theapp_light</item> </style> <style name="DropDownListView.theapp_light" parent="@style/Widget.AppCompat.Light.ListView.DropDown"> <item name="android:listSelector">@drawable/selectable_background_theapp_light</item> </style> <style name="ActionBarTabStyle.theapp_light" parent="@style/Widget.AppCompat.Light.ActionBar.TabView"> <item name="android:background">@drawable/tab_indicator_ab_theapp_light</item> </style> <style name="DropDownNav.theapp_light" parent="@style/Widget.AppCompat.Light.Spinner.DropDown.ActionBar"> <item name="android:background">@drawable/spinner_background_ab_theapp_light</item> <item name="android:popupBackground">@drawable/menu_dropdown_panel_theapp_light</item> <item name="android:dropDownSelector">@drawable/selectable_background_theapp_light</item> </style> <style name="ProgressBar.theapp_light" parent="@style/Widget.AppCompat.ProgressBar.Horizontal"> <item name="android:progressDrawable">@drawable/progress_horizontal_theapp_light</item> </style> <style name="ActionButton.CloseMode.theapp_light" parent="@style/Widget.AppCompat.Light.ActionButton.CloseMode"> <item name="android:background">@drawable/btn_cab_done_theapp_light</item> </style> <!-- this style is only referenced in a Light.DarkActionBar based theme --> <style name="Theme.theapp_light.Widget" parent="@style/Theme.AppCompat"> <item name="popupMenuStyle">@style/PopupMenu.theapp_light</item> <item name="dropDownListViewStyle">@style/DropDownListView.theapp_light</item> </style> </resources>

And this is color resources style located in res\values

<resources> <color name="pressed_theapp_light">#CCFC4C5D</color> </resources>


<strong>EDIT</strong>: I updated all the content below to include the style multiListItem that I defined to setup an automated style on the list items.

Here is the way I use on my app to let the user switch between themes:

First I prepare the different themes in the file styles.xml, here is an easy example where I modify the default basic colors on the system:

<!-- *** DEFAULT THEME *** --> <style name="AppTheme" parent="@android:style/Theme.Holo.Light"> <item name="android:textColorPrimary">?mainColor</item> <item name="android:textColorSecondary">?darkColor</item> <item name="android:textColorTertiary">?lightColor</item> </style> <!-- *** ORANGE THEME *** --> <style name="AppThemeOrange" parent="@style/AppTheme"> <item name="mainColor">@color/orange_main</item> <item name="lightColor">@color/orange_light</item> <item name="darkColor">@color/orange_dark</item> <item name="multiListItem">@style/OrangeListViewItemStyle</item> </style> <!-- *** PURPLE THEME *** --> <style name="AppThemePurple" parent="@style/AppTheme"> <item name="mainColor">@color/purple_main</item> <item name="lightColor">@color/purple_light</item> <item name="darkColor">@color/purple_dark</item> <item name="multiListItem">@style/PurpleListViewItemStyle</item> </style>

I also add the 2 styles needed for the 2 themes:

<style name="OrangeListViewItemStyle"> <item name="android:textColor">@color/OrangeMain</item> <item name="android:textSize">18sp</item> </style> <style name="PurpleListViewItemStyle"> <item name="android:textColor">@color/PurpleMain</item> <item name="android:textSize">20sp</item> </style>

The style multiListItem is then called on the list row items, for this case I used it in this layout (the layout inflated for each row in my list):

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/filter_list_child_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:background="?android:attr/activatedBackgroundIndicator" android:orientation="horizontal" > <CheckBox android:id="@+id/filter_list_child_checkbox" android:layout_width="wrap_content" android:layout_height="wrap_content" android:clickable="false" android:focusable="false" android:focusableInTouchMode="false" android:longClickable="false" /> <TextView android:id="@+id/filter_list_child_textview" style="?multiListItem" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" /> </LinearLayout>

So I have a default theme that is actually loading references from the specific Orange and Purple themes. In order to do this I added the references in the file values\attrs.xml:

<?xml version="1.0" encoding="utf-8"?> <resources> <attr name="mainColor" format="reference"/> <attr name="lightColor" format="reference"/> <attr name="darkColor" format="reference"/> <attr name="multiListItem" format="reference" /> </resources>

I also created all the selectors I call in the styles in the folder color, here is orange_dark.xml for example:

<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android" > <item android:state_enabled="false" android:color="@color/TextGray"/> <item android:state_pressed="true" android:color="@color/OrangeLightBackground"/> <item android:color="@color/OrangeDark"/> </selector>

Once all this is prepared, I load the right theme using the shared preferences. The theme is just available as a normal setting through a list preference populated with this:

<string-array name="themes_strings"> <item>Purple</item> <item>Orange</item> </string-array> <string-array name="themes_values"> <item>purple</item> <item>orange</item> </string-array>

Then to retrieve the theme selected in the settings, I just use this simple function:

public int getThemeID() { String themeSelected = _sharedPrefs.getString(PREF_KEY_THEME, DEFAULT_THEME); if(themeSelected.equalsIgnoreCase("orange")){ return THEME_ORANGE_ID; } else if(themeSelected.equalsIgnoreCase("purple")){ return THEME_PURPLE_ID; } else{ return THEME_PURPLE_ID; } }

The constants are defined using the themes references directly:

public static final int THEME_ORANGE_ID = R.style.AppThemeOrange; public static final int THEME_PURPLE_ID = R.style.AppThemePurple;

Then the theme selected is applied on the activities using this line:


mPrefs is just a helper class gathering all my shared preferences getters and setters.

Hope it will give you some ideas!


  • How do I redirect to another webpage?
  • How to draw a chart like below using chart js
  • Initial commit of major projects to mercurial
  • ASP.NET MVC 5 Ninject: Ninject.MVC3/5
  • Mailchimp - how can I tell if a user has unsubscribed themselves?
  • Can the Microsoft TextTransform utility be used standalone?
  • Magento SOAP API v2 shoppingCartProductAdd error “One item of products do not have identifier or sku
  • Variant of defaultdict for assigning value only once
  • Converting a data frame into named object in R
  • Entity framework - Foreign key - data annotation
  • Pass large string into api controller by $http angular service
  • How can i compile & run a c program (with OpenMP) in gem5 Full System?
  • Per Machine App Registration
  • File extension of zlib zipped html page?
  • iOS Cordova first plugin - plugin.xml to inject a feature
  • Can't locate Module/Build.pm in @INC (@INC contains: /usr/local/lib64/perl5
  • Most efficient way to move table rows from one table to another
  • How to use function wrapper in mustache.php?
  • C# fibonacci function returning errors
  • How to get current document uri in XSLT?
  • std::remove_copy_if_ valgrind bytes in block are possibly lost in loss record
  • Convert Type Decimal to Hex (string) in .NET 3.5
  • What is the purpose of TaskExecutor in spring?
  • How to get Eclipse Oxygen to run on Java 9
  • Problem deserializing objects from cache on MyBatis 3/Java
  • Functions in global context
  • Cannot connect to cassandra from Spark
  • Optimizing database types to compact database (SQLite)
  • Cross-Platform Protobuf Serialization
  • Deserializing XML into class C#
  • Do I've to free mysql result after storing it?
  • Warning: Can't call setState (or forceUpdate) on an unmounted component
  • XCode can't find symbols for a specific iOS library/framework project
  • bootstrap to use multiple ng-app
  • How to get icons for entities from eclipse?
  • How to include full .NET prerequisite for Wix Burn installer
  • Turn off referential integrity in Derby? is it possible?
  • JaxB to read class hierarchy
  • costura.fody for a dll that references another dll
  • jQuery Masonry / Isotope and fluid images: Momentary overlap on window resize