Change ActionBar Menu Icons depending on Style - android

I want to use different ActionBar Icons depending on which style I use (Dark or Light).
I couldn't figure it out how, heres what I tried:
<style name="AppThemeDark" parent="Theme.Sherlock.ForceOverflow">
<item name="android:actionButtonStyle">#style/customActionButtonStyleDark</item>
<item name="actionButtonStyle">#style/customActionButtonStyleDark</item>
</style>
<style name="AppThemeLight" parent="Theme.Sherlock.Light.ForceOverflow">
<item name="android:actionButtonStyle">#style/customActionButtonStyleLight</item>
<item name="actionButtonStyle">#style/customActionButtonStyleLight</item>
</style>
<style name="customActionButtonStyleDark" >
<item name="#drawable/action_search">#drawable/action_search</item>
</style>
<style name="customActionButtonStyleLight" >
<item name="#drawable/action_search">#drawable/action_search_light</item>
</style>
I also tried to insert <item name="#drawable/action_search">#drawable/action_search</item> directly into the theme style, but nothing worked.
Any ideas how?

Even though you found a workaround, maybe this will help someone else. I found a simple way to do this in xml (what logcat's answer is referring to). The trick I used was to create custom attributes for my menu/actionbar icons. You have to have one attribute per menu item icon.
You need to create attrs.xml in your values folder, and add your custom attributes. Think of each attribute as a constant that your themes/styles set, and then your styles/views can use those contants to set properties.
<declare-styleable name="customAttrs">
<attr name="customSearchIcon" format="reference" />
</declare-styleable>
In your styles.xml in your values folder, have your themes/styles that set your custom icon attributes to drawable references.
<style name="AppThemeDark" parent="Theme.Sherlock.ForceOverflow">
<item name="customSearchIcon">#drawable/action_search</item>
</style>
<style name="AppThemeLight" parent="Theme.Sherlock.Light.ForceOverflow">
<item name="customSearchIcon">#drawable/action_search_light</item>
</style>
Lastly, in your [menu_name].xml in your menu folder, have your menu item set its icon to your matching custom icon attribute.
<item
android:id="#+id/menuitem_search"
android:icon="?attr/customSearchIcon"/>
Now, depending on what theme is set, the icon for the menu item will change. Also, this allows you to still have API specific versions of your drawables (light and dark) using resource identifiers with your drawable folders, so you can have different menu style icons for pre 3.0 and actionbar style icons for 3.0+.
Also, remember when setting a theme at runtime (vs AndroidManifest.xml), you must set it before calling setContentView() in your Activity. It is recommended to restart your activity after changing the theme of an Activity that has already been created.

I think you did not get theming :) When you are trying to do:
<style name="customActionButtonStyleDark" >
<item name="#drawable/action_search">#drawable/action_search</item>
</style>
You are trying to overload some attribute in theme with name "#drawable/action_search"
I have bad news for you, I think there is no such. So you can go to the theme Theme.Sherlock.ForceOverflow and it's parents and see what you can overload.
If nothing help's you, and you want to have custom attribute in your theme for different icons, It's different topic. You need to create attribute in attrs.xml, point your icon source to this new attribute and define attribute value in theme. For every different button.

Solved it, but gave it up to try it with XML, I did it now programmatically:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
SharedPreferences prefs = getSharedPreferences("app", 0);
boolean isDark = "Dark".equals(prefs.getString("theme", "Dark"));
com.actionbarsherlock.view.MenuInflater inflater = getSupportMenuInflater();
inflater.inflate(R.menu.main, menu);
// set Icons
menu.findItem(R.id.menuitem_search).setIcon(isDark ? R.drawable.action_search : R.drawable.action_search_light);
menu.findItem(R.id.menuitem_add).setIcon(isDark ? R.drawable.content_new : R.drawable.content_new_light);
menu.findItem(R.id.menuitem_share).setIcon(isDark ? R.drawable.social_share : R.drawable.social_share_light);
return true;
}

See res/xml/ic_search.xml in blog post AppCompat — Age of the vectors (Chris Barnes)
Notice the reference to ?attr/colorControlNormal
<vector xmlns:android="..."
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="?attr/colorControlNormal">
<path
android:pathData="..."
android:fillColor="#android:color/white"/>
</vector>

Related

Drawable as styleable and how themes are selected

In this code ToolbarWidgetWrapper
I see that the Drawable is defined as styleable.
I tried to find what is that drawable and I found definitions such as:
res/res/values/themes.xml: <item name="homeAsUpIndicator">#drawable/ic_ab_back_holo_dark</item>
res/res/values/themes_holo.xml: <item name="homeAsUpIndicator">#drawable/ic_ab_back_holo_dark</item>
res/res/values/themes_holo.xml: <item name="homeAsUpIndicator">#drawable/ic_ab_back_holo_light</item>
res/res/values/themes_holo.xml: <item name="homeAsUpIndicator">#drawable/ic_ab_back_holo_dark</item>
res/res/values/styles.xml: <item name="collapseIcon">?attr/homeAsUpIndicator</item>
res/res/values/themes_material.xml: <item name="homeAsUpIndicator">#drawable/ic_ab_back_material</item>
res/res/values/themes_material.xml: <item name="homeAsUpIndicator">#drawable/ic_ab_back_material</item>
It seems that this kind of definition ensures that the icon corresponds to the app's theme and I see the icons are completely different in each definition.
Is that right? And if so, I was wondering how exactly the corresponding file is being selected? Does it depend only on some app configuration about the theme?
Is there a case that none of these would be selected?

Change Drawable Based on Theme

I've got an image in two different colors, corresponding to two different themes in Android. I want to use them in my Action Bar. I want to refer to a drawable for the icon, theme agnostic, but have that drawable reference the light color for the light theme, and the dark color for the light theme.
In the menu:
<item
android:id="#+id/menu_attach_existing_picture"
android:icon="#drawable/buttonface_picture"
android:showAsAction="always"
android:title="#string/menu_attach_existing_picture">
</item>
Then in the styles I want to have something that maps #drawable/buttonface_picture to #drawable/buttonface_picture_light in the light theme and #drawable/buttonface_picture_dark for the dark theme.
I feel like there's got to be a way, but I'm having trouble finding the syntax. If it changes anything, I am using ActionBarSherlock.
Seems like I'm always just a Google search or two away from my answers. The solution is:
in styles.xml
<attr name="buttonface_picture" format="reference"/>
then in the actual theme:
<item name="buttonface_picture">#drawable/buttonface_picture_dark</item>
or
<item name="buttonface_picture">#drawable/buttonface_picture_light</item>
Then, in the menu.xml:
<item
android:id="#+id/menu_attach_existing_picture"
android:icon="?attr/buttonface_picture"
android:showAsAction="always"
android:title="#string/menu_attach_existing_picture">
</item>
The Accessing Resources Page combined with this SO eventually got it to click in my brain.

Dynamic themes and custom styles

I've got an app with two themes (dark and light) that can be selected at runtime. This works. I also have a ListView with rows that can have one of three different layouts, each of which has a style (say, different colors). This also works. But I can't get these two features to work together. I really need six different styles, three for one theme (dark) and three for the other (light), but I can't figure out how to choose a style for a list item based on the current theme, or get that effect any other way by using XML files. My three layouts each point to a custom theme that sets the color, but that overrides whatever theme I've got set. Themes can only contain items that are "styleable", so I can't put my own custom items in there. There may be a way to do this programmatically, but I was hoping to do it declaratively. Any ideas?
Thanks to wingman for the hint. My situation involved colors, which are a bit more complicated, so I'll write up my solution here.
I have two themes (light and dark) which the user can choose from in the Settings screen. I have a ListView which can have two types of rows (plain and note), each with its own styling. Firstly each layout needs to point to a style:
<TextView style="#style/PlainItemText" ... />
(or NoteItemText) and we need to define the styles:
<style name="PlainItemText">
<item name="android:textSize">#dimen/list_item_font_size</item>
<item name="android:textStyle">bold</item>
<item name="android:textColor">?plainTextColor</item>
</style>
The text color can't be fixed because it depends on the selected theme. We must create a custom attribute and refer to it with a question mark, as above. We define the attribute in res/values/attrs.xml:
<!-- Attributes we use to set the text color of the various list items. -->
<attr name="plainTextColor" format="reference|color"/>
<attr name="noteTextColor" format="reference|color"/>
We can then define the various colors. Here we have two styles and two themes, so we need four color state lists, each in its own file under res/color. For example, here's res/color/plain_text_color_dark.xml:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_window_focused="false" android:color="#android:color/white"/>
<item android:state_selected="true" android:color="#android:color/black"/>
<item android:state_focused="true" android:color="#android:color/black"/>
<item android:state_pressed="true" android:color="#android:color/black"/>
<item android:color="#android:color/white"/>
</selector>
The selected/focused/pressed colors are the same in all these files because they're over the highlight color. Be careful with the state_window_focused version. It didn't behave as advertised, and I had to set it to the default color (the last line above) in all cases. Now we need to create our themes and bind the attributes to one of the colors. These lines go into res/values/themes.xml:
<style name="Theme.Dark" parent="android:Theme">
<item name="plainTextColor">#color/plain_text_color_dark</item>
<item name="noteTextColor">#color/note_text_color_dark</item>
</style>
<style name="Theme.Light" parent="android:Theme.Light">
<item name="plainTextColor">#color/plain_text_color_light</item>
<item name="noteTextColor">#color/note_text_color_light</item>
</style>
Finally we pick a theme at run-time, in an Activity's onCreate() method, before calling super.onCreate():
if (isDarkTheme) {
activity.setTheme(R.style.Theme_Dark);
} else {
activity.setTheme(R.style.Theme_Light);
}
Note that I don't take into account newer themes like Holo, so my app looks old on Honeycomb and later. I'll fix that at some point, but it wasn't a regression here.
A twist in my case is that some Activities have a larger title bar in order to fit some buttons. In principle I should have created four themes, a light and dark for a narrow title and a light and dark for a fat title. But instead I created a mix-in style:
<!-- Mix-in style for activities. -->
<style name="ButtonTitleBar">
<item name="android:windowTitleSize">44dp</item>
</style>
and procedurally add it to whatever theme I'm using. This code goes right after the above setTheme() calls:
if (buttonTitleBar) {
// Mix in this other style.
Resources.Theme theme = activity.getTheme();
theme.applyStyle(R.style.ButtonTitleBar, true);
}
I didn't see this documented anywhere, and I don't know if it's legit, but the code of Activity.getTheme() implies that it should work fine, and it has worked in all my testing. This can help avoid the combinatorial explosion of themes that you can find in the standard Android theme list.
It's a long time ago that Lawrence Kesteloot published his solution in 2012. Now it is six years later, a am new in Android and try to solve the similar problem:
How can I exchange the whole style of the application by just exchanging one theme?
This is a generalisation of Lawrences issue how to organise two exchangeable themes.
I figured out a solution based on Lawrence's and going a step further.
(Not claiming it is the perfect solution, yet an improvement.)
Lawrence figured out the power of user defined attributes to reach this goal. He uses them to address colours depending on the the currently selected theme.
While this is working it still requires to define attributes for each and every property. It doesn't scale well. So why not bundling the properties into styles and themes and using the same mechanism?
This results in a master theme, that is defining child themes and styles.
res/values/attrs.xml
<resources>
...
<attr name="mainViewTheme" format="string"/>
<attr name="asideViewTheme" format="string"/>
...
</resources>
When defining the attribute to set a theme, there is no special format for it. The format string does it.
res/values/styles.xml
<style name="MasterTheme">
...
<item name="mainViewTheme">#style/MainViewTheme</item>
<item name="asideViewTheme">#style/AsideViewTheme</item>
...
</style>
<style name="MainTextTheme">
...
</style>
<style name="MainViewTheme">
...
</style>
res/layouts/main.xml
<TextView
android:theme="?mainViewTheme"
...
By exchanging the master theme all styles are adjusted. It still requires the definition of a handful of theme attributes and then does a powerful job. Setting up attributes for every property is not required any more.

AutoCompleteTextView dropDownSelector

I have an AutoCompleteTextView component and I want to change its default drop down selector to another color. First I tried: android:dropDownSelector="#FF400000", but it caused no selector to appear at all! Next I put the color in a drawable resource:
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#android:color/holo_blue_dark"/>
</shape>
And linked it: android:dropDownSelector="#drawable/drop_down_selector", but that did the same effect (no selector). Next I found a similar issue someone opened, just for spinner: http://code.google.com/p/android/issues/detail?id=24922, so I tried defining a style as was explained in the solution there:
<style name="AutoCompleteDropDown" parent="#android:style/Theme.Holo.Light">
<item name="android:dropDownListViewStyle">#style/AutoCompleteSelector</item>
</style>
<style name="AutoCompleteSelector" parent="#android:style/Widget.Holo.Light.ListView">
<item name="android:listSelector">#FF400000</item>
</style>
And linked it: style="#style/AutoCompleteDropDown", but it did nothing (however, the default selector got back since I removed the dropDownSelector attribute).
So what am I missing here? What am I doing wrong?
UPDATE: Ok, so as was suggested, I also tried a selector:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:state_pressed="true"
android:state_focused="true" android:state_activated="true"
android:drawable="#android:color/holo_green_light"/>
</selector>
But it didn't work, I still get no selector (at least not one I can see).
Theme's and styles are different by intent. And use different attributes. Theme define style for different widgets. Style define the widgets itself. Theme's are applied to application or activities.
1) If you want it to be for just one widget.
You need to go to /platforms//res/values/values.xml, find out how styles is defined for your widget (AutoCompleteTextView). Pick up required attribute. Define the same selector like in system but with your modifications. And you can even find out the selector in /res/drawable
2) If you want to be it all over the application:
a)You need to go to /platforms//res/values/themes.xml
b) There you can find out which style are in the theme you chose for AutoCompleteTextViewb
<item name="autoCompleteTextViewStyle">
#android:style/Widget.AutoCompleteTextView
</item>
c) Then got to res/values/styles.xml
d) There you can find out the style for widget.
e) Then you need to extend theme. And override autoCompleteTextViewStyle attribute by your new created style like in 1 option.
Try remove background from your views, which generated by adapter. That has helped me.

What style attribute has to be changed for spinner dropdownitem?

I would like to change the color when a item of the spinner drop down is clicked.
I searched all the way through themes.xml, styles.xml and attr.xml but yet I can find which attribute has to be set to achieve this.
In attr.xml there is
<attr name="spinnerDropDownItemStyle" format="reference" />
In themes.xml in default themse there is
<style name="Theme">
...
<item name="spinnerDropDownItemStyle">#android:style/Widget.DropDownItem.Spinner</item>
<item name="spinnerItemStyle">#android:style/Widget.TextView.SpinnerItem</item>
...
When I follow this in style.xml I cant find any entry where the background drawable (with selectors for pressed and focused) is assigned (I guess there must be somewhere a refference to a xml file with selectors inside, like for button).
In short: I cant find what has to be set how in order to change the click and focus appearance of spinner dropdown items.
The Background alone can be changed by
<style name="CustomSpinnerAppearance0" parent="android:style/Widget.Holo.Light.Spinner">
<item name="android:background">#drawable/spinner_default0</item>
<item name="android:dropDownSelector">#ffc0c0c0</item>
<item name="android:popupBackground">#ffc0c0c0</item>
</style>
But even when I set a selector or transition as popupBackground nothing changes in the click behaviour.
Any ideas?
Thanks.
Meanwhile I found the solution.
To close this question:
I still dont know, why it has no influence on the behaviour when I set the dropDownSelector.
But changing the attribute
<item name="android:listChoiceBackgroundIndicator"></item>
does the trick.

Categories

Resources