
Question:
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>
Answer1:<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:
setTheme(mPrefs.getThemeID());
mPrefs
is just a helper class gathering all my shared preferences getters and setters.
Hope it will give you some ideas!