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?
Related
I'm trying to create a more accessible, high-contrast mode for my app.
My current setup is as follows:
<style name="AppTheme" parent="Theme.MaterialComponents.Light.DarkActionBar.Bridge">
<item name="colorPrimary">#color/primary_color</item>
<item name="colorPrimaryDark">#color/primary_color_dark</item>
<item name="colorAccent">#color/primary_color</item>
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:windowBackground">#color/background_fixed</item>
<item name="listPopupWindowStyle">#style/ListPopupWindow</item>
</style>
In the colors.xml file, is where I store all of the colours I use throughout the application.
All of the colours within colors.xml will need to slightly change if the user ticks "Accessibility mode". The solution I came up with was that I could create a copy of the original colors.xml file, but with the high contrast versions of the original colours, and when a user ticks the accessibility toggle, it will programmatically switch to the "accessibility_colors.xml" file (in which colours will be named identically to the original, but with different values)
I have done some research but can't find any information on this. Is this possible? If not - what is a viable solution for this?
Color resources ids are generated during compiling time. So if you have a colors.xml file for default and another for, let's say a "night theme", you won't be able to do this programmatically on runtime.
One possible solution for this, would be to have this colors you need for "accessibility mode" to be created programmatically (hexadecimal code in code).
For example:
fun getPrimaryColor(isAccessibilityMode): Int {
return if(isAccessibilityMode) {
Color.parseColor("#bdbdbd");
} else {
Color.parseColor("#efefef"); // completely random colors here :)
}
}
You the would have to override the views default colors that you usually set in the theme style.
I am setting my icon in an ImageButton like this:
<ImageButton
style="#style/LeafPlayerMediaButton.Like"
... />
styles.xml
<style name="LeafPlayerMediaButton.Like">
<item name="android:src">#drawable/ic_app_heart_border</item>
<item name="android:contentDescription">#string/action_like</item>
</style>
#drawable/ic_app_heart_border was PNG files. However, now I upgraded to vector drawables. I know that if I set a vector drawable into an ImageView I should use app:srcCompat=#drawable/ic_app_heart_border.
While using vector drawables,if I use:
<item name="android:src">#drawable/ic_app_heart_border</item>
the app crashes for API < 21.
And if I use:
<item name="app:srcCompat">#drawable/ic_app_heart_border</item>
the app don't even start saying that app:srcCompat is not valid. What should I do?
Remove the 'app:' part of your styles.xml item.
So it'd be:
<item name="srcCompat">#drawable/ic_app_heart_border</item>
Any items with custom namespaces (anything other than 'android' and 'tools') should have their name space removed when put into 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.
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.
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>