Themes in Android are mixing - android

I have an app and I define to themes "A" and "B" inside the themes a define a set of styles
<resources>
<style name="Theme.A" parent="Theme.Base.AppCompat">
</style>
<style name="btnMiniPlayer" parent="Theme.A">
<item name="android:background">#drawable/image1</item>
</style>
<resources>
<style name="Theme.B" parent="Theme.Base.AppCompat">
</style>
<style name="btnMiniPlayer" parent="Theme.B">
<item name="android:background">#drawable/image2</item>
</style>
So I have in my app a property in a button
style="#style/button"
Depends of the style I need to change the image, also I set in the manifest the theme but the app is mixing the styles so for now I set the "A" like the primary theme but the app show the images from theme "B".
Any idea???

Do something like this:
<style name="button" parent="A">
<item name="android:background">#drawable/image</item>
</style>
drawable/image.xml:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false" android:drawable="#drawable/image1" />
<item android:state_pressed="true" android:drawable="#drawable/image2" />
</selector>
There are also things like:
android:state_selected="true"

I found how to answer my question, so you need to follow the next steps in order to fix it
1- Create an attribute in my case I set the name like myButton:
<declare-styleable name="def_Styles">
<attr name="myButton" format="reference" />
</declare-styleable>
2- In every Theme ("A" and "B") you have to define the item
<resources>
<style name="Theme.B" parent="Theme.Base.AppCompat">
<item name="myButton">#style/CustomButtonB</item>
</style>
<style name="CustomButtonB" parent="Theme.B">
<item name="android:background">#drawable/image2</item>
</style>
3- In the view just set the style to the correct attribute
style="?myButton"
If you change the theme in the manifest between A and B it will be work

Related

How to use Android styles inheritance with different qualifiers

I'm working on Android app and I have to support API 19 and higher. So my styles structure looks like this:
res
values
styles.xml
values-v21
styles.xml
In styles.xml I have
<style name="customButton" parent="Base.Widget.AppCompat.Button">
<item name="android:focusable">false</item>
<item name="android:clickable">true</item>
</style>
and in the v21/styles.xml I have
<style name="customButton" parent="customButton">
<item name="android:elevation">10dp</item>
</style>
While this works, it doesn't seem right. And the Android studio is complaining about cyclic references. That is because the v21/customButton has technically itself as a parent.
I cannot rename the v21/customButton to customButton21 because then I would have to create two versions of everything that uses this style. While only difference is the new attribute added in API 21.
What is the correct way to solve this issue? Maybe create base-style.xml and then reference it in specific API styles?
PS: This question applies to any qualifiers, not only the API.
I have settled for following solution:
attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="buttonStyle" format="reference" />
</resources>
values/styles.xml
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="#attr/buttonStyle">#style/buttonStyleBase</item>
</style>
<style name="buttonStyleBase">
<item name="android:gravity">left</item>
<item name="android:textSize">20sp</item>
</style>
</resources>
values-v21/styles.xml
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="#attr/buttonStyle">#style/buttonStyle21</item>
</style>
<style name="buttonStyle21" parent="buttonStyleBase">
<item name="android:elevation">15dp</item>
</style>
</resources>
And then to use it:
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
style="?attr/buttonStyle" />
This way I can inherit the base style which can be as complex as I need and apply only changes that are relevant to another SDK version.

Android Use custom themes to modify style attributes

I want to create two themes, GrayTheme and RedTheme, that modify one style attribute. For example here are my two themes, default font color is white, which is fine for both themes:
<style name="RedTheme" parent="#style/Theme.AppCompat.Light.DarkActionBar">
<item name="android:textColor">#color/white</item>
</style>
<style name="GrayTheme" parent="#style/Theme.AppCompat.Light.DarkActionBar">
<item name="android:textColor">#color/white</item>
</style>
But I have a style that I use for Header TextViews. If I am using the RedTheme I want the style HeaderFont to have textColor red and if it is the GrayTheme I want the HeaderFont textColor to be gray, without me having to modify the individual xml files that access this HeaderFont style.
<style name="HeaderFont" parent="#android:style/TextAppearance.Medium">
<item name="android:textColor">#color/gray</item>
</style>
I've been searching around looking for a graceful solution to this, but haven't been able to find anything. Ideas?
After many failures of finding a clean solution I finally found an answer that works beautifully.
I created a custom attribute headerFontColor and added it to /res/values/attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="headerFontColor" format="reference|color" />
</resources>
Next, in the style for HeaderFont I added updated the textColor to be the new custom attribute (headerFontColor) instead of a specific color
<style name="HeaderFont" parent="#android:style/TextAppearance.Medium">
<item name="android:textColor">?headerFontColor</item>
</style>
Now, I can simply set the headerFontColor attribute based on the theme
<style name="RedTheme" parent="#style/Theme.AppCompat.Light.DarkActionBar">
<item name="android:textColor">#color/white</item>
<item name="headerFontColor">#color/red</item>
</style>
<style name="GrayTheme" parent="#style/Theme.AppCompat.Light.DarkActionBar">
<item name="android:textColor">#color/white</item>
<item name="headerFontColor">#color/gray</item>
</style>
After doing this, all TextViews that use the HeaderFont style get updated with the headerFontColor just by switching the Theme
This solution guided me: Setting a color based on theme
I used references from google's iosched project.
Created an attrs.xml file in res/values/
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="Theme">
<attr name="headerFontColor" format="color" />
</declare-styleable>
</resources>
Then in themes.xml
<style name="RedTheme" parent="#style/Theme.AppCompat.Light.DarkActionBar">
<item name="headerFontColor">#color/red</item>
</style>
<style name="GrayTheme" parent="#style/Theme.AppCompat.Light.DarkActionBar">
<item name="headerFontColor">#color/gray</item>
</style>

In Android, can apply different themes in a single XML layout's TextView at runtime without creating a custom widget?

I've seen similar questions here before, but none of them had a satisfactory answer. Basically, I want to have one layout instead of multiple ones and be able to apply themes at runtime. For example, let's take this layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
xmlns:android="http://schemas.android.com/apk/res/android" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="SAMPLE HEADING"
style="#style/Heading" />
</LinearLayout>
And the themes and styles are set up as follows:
<style name="AppTheme.Dark" parent="AppTheme">
<item name="android:radioButtonStyle">#style/radioButton.Dark</item>
<item name="android:checkboxStyle">#style/checkbox.Dark</item>
</style>
<style name="AppTheme.Light" parent="AppTheme">
<item name="android:radioButtonStyle">#style/radioButton.Ios</item>
<item name="android:checkboxStyle">#style/checkbox.Ios</item>
</style>
<style name="Heading">
<item name="android:typeface">sans</item>
<item name="android:textStyle">bold</item>
</style>
<style name="Heading.Dark" parent="Heading">
<item name="android:textColor">#color/red</item>
<item name="android:background">#drawable/dark_bg</item>
<item name="android:textSize">16dip</item>
</style>
<style name="Heading.Light" parent="Heading">
<item name="android:textColor">#color/black</item>
<item name="android:background">#drawable/light_bg</item>
<item name="android:textSize">17dip</item>
</style>
So, I want to be able to apply the dark and light Heading styles to that TextView by simply applying the dark or light AppTheme. And I don't want to apply those styles to all TextViews, but only specific ones. I also don't want to do this programmatically because there are way too many TextViews that would need this done.
Is there a way to do that, or do i have to create two identical XML layouts, where one uses the Heading.Light style and the other uses Heading.Dark?
First, your use of parent="..." property is incorrect.
As official docs state:
"If you want to inherit from styles that you've defined yourself, you do not have to use the parent attribute. Instead, just prefix the name of the style you want to inherit to the name of your new style, separated by a period."
So, declaring your style name as Heading.Light is enough to specify that it's parent style is Heading.
Now to your question. Create a res/values/attrs.xml file:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="myTextViewColor" format="reference|color" />
</resources>
Then in your styles.xml you would declare your theme as follows:
<style name="AppTheme">
<!--parent style. could be overriden by Dark and Light theme -->
</style>
<style name="AppTheme.Dark">
...
<item name="myTextViewColor">#color/red</item>
</style>
<style name="AppTheme.Light">
...
<item name="myTextViewColor">#color/black</item>
</style>
<style name="Heading">
<item name="android:typeface">sans</item>
<item name="android:textStyle">bold</item>
<item name="android:textSize">16dip</item>
</style>
Now when you apply
<TextView ... style="#style/Heading" android:textColor="?myTextViewColor />
everything should work just fine. Just make sure you apply AppTheme.Light or AppTheme.Dark theme in your app (as AppTheme parent theme would not know the value of your custom attribute).
Edit: Also, as user496854 suggested, there's another simple workaround.
Declare headingStyle attr as a reference:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="headingStyle" format="reference" />
</resources>
Then in our AppTheme.Dark and AppTheme.Light styles we would point to a corresponding heading style:
<style name="AppTheme.Dark">
...
<item name="headingStyle">#style/Heading.Dark</item>
</style>
<style name="AppTheme.Light">
...
<item name="headingStyle">#style/Heading.Light</item>
</style>
I would suggest you to crate a class that extends TextView and apply your style in it. Use this textView where you want textview with this them and simple TextView where you don't need.

Define different themable styles to the same widget types

I would like to define different themable styles for Android widget. In example below there are two ImageView widgets, where one is using my 'theme' style and another is manualy styled. I wish to implement config files in a way that I coluld ommit 'base_theme' prefix so it could be determined automatically based on activity theme configuration.
Documentation on writing themes mentions how to change style for all ImageViews or Buttons, not for particular ones with style attribute. I figured out that it is possible to solve my problem by using stylable custom components but I think there is some better way to solve my problem.
base_style.xml
<style name="base_theme" parent="android:Theme.NoTitleBar">
</style>
<style name="base_theme.event_list_filter">
<item name="android:orientation">horizontal</item>
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_margin">10dp</item>
<item name="android:background">#drawable/base_white_rounded</item>
</style>
<style name="base_theme.base_event_list_filter_image">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:padding">10dp</item>
<item name="android:background">#drawable/vr_black_border</item>
</style>
<style name="base_theme.base_event_list_scrollable">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">0dp</item>
<item name="android:layout_weight">1</item>
<item name="android:background">#drawable/base_white_rounded</item>
</style>
<style name="base_theme.base_event_list_table">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">fill_parent</item>
</style>
activity_layout.xml
<LinearLayout style="#style/base_theme.base_event_list_filter" >
<ImageView
style="#style/base_theme.base_event_list_filter_image"
android:src="#drawable/pic0" />
<ImageView
...
android:src="#drawable/pic1" />
</LinearLayout>
Thanks for help,
Maciek
I have found a solution. I hope it will help someone with similar theming problem.
First of all I have added new attributes to my base_theme, and then I have configured them in following way:
base_style.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- add attributes to your theme -->s
<declare-styleable name="base_theme">
<attr name="event_list_filter" format="reference" />
<attr name="pic0" format="reference" />
</declare-styleable>
<!-- fill attributes with your own styles/drawables/etc -->
<style name="base_theme" parent="android:Theme.NoTitleBar">
<item name="event_list_filter">#style/base_theme.event_list_filter_image</item>
<item name="pic0">#drawable/base_theme.pic0</item>
</style>
<!-- define corresponding resource -->
<style name="base_theme.base_event_list_filter_image">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:padding">10dp</item>
<item name="android:background">#drawable/vr_black_border</item>
</style>
<drawable name="base_theme.pic0">#drawable/base_pic0</drawable>
</resources>
Another layout steel_styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- fill attributes with your own styles/drawables/etc -->
<style name="steel_theme" parent="#style/base_theme">
<item name="pic0">#drawable/steel_theme.pic0</item>
</style>
<drawable name="steel_theme.pic0">#drawable/steel_pic0</drawable>
</resources>
Activity layout file activity_layout.xml
...
<ImageView
style="?attr/event_list_filter_image"
android:src="?attr/pic0" />
...
With such configuration pic0 will be different on the screen based on theme set for activity in AndroidManifest.xml.

How to reference from drawable to style

My app with tabs has two themes. In each theme tabs have different images in selected and unselected state. How I can properly reference to image by theme?
For example. I have in themes.xml
<?xml version="1.0" encoding="utf-8"?>
<style name="LightTheme" parent="#android:style/Theme.Light">
<item name="tabShows">#drawable/ic_tab_shows_unselected_light</item>
<item name="tabShowsSelected">#drawable/ic_tab_shows_selected_light</item>
<item name="tabNews">#drawable/ic_tab_news_selected_light</item>
<item name="tabNewsSelected">#drawable/ic_tab_news_unselected_light</item>
</style>
<style name="DarkTheme" parent="#android:style/Theme.Black">
<item name="tabShows">#drawable/ic_tab_shows_unselected_dark</item>
<item name="tabShowsSelected">#drawable/ic_tab_shows_selected_dark</item>
<item name="tabNews">#drawable/ic_tab_news_selected_dark</item>
<item name="tabNewsSelected">#drawable/ic_tab_news_unselected_dark</item>
</style>
Also I have a tab_shows.xml and tab_news.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:drawable="#drawable/ic_tab_shows_selected_light"/>
<item android:state_selected="false" android:drawable="#drawable/ic_tab_shows_unselected_light" />
How I can reference to needed image in selector according to current theme?
This not work for me
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:drawable="?tabShowsSelected"/>
<item android:state_selected="false" android:drawable="?tabShows" />
In layout files this works, I mean reference to style via ?styleName
Build your style A and style B
in your case you put android:drawable="#drawable/ic_tab_shows_selected_light" instead of background (I just copied snipets from my code)
#000
<style name="styleB">
<item name="android:background">#000</item>
</style>
your theme A
<style name="Theme.A">
<item name="pageBackground">#style/styleA</item>
</style>
theme B
<style name="Theme.Blue">
<item name="pageBackground">#style/styleB</item>
</style>
in your attr.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="pageBackground" format="reference" />
</resources>
finally in your widget you do style="?pageBackground"
You can find your answer here
http://www.androidengineer.com/2010/06/using-themes-in-android-applications.html
Edit
(Additional information by Lukap in comments)
Define one or more themes in themes.xml and set the definitions of your styles there.
Define custom attributes, a.k.a. custom styles, in attrs.xml.
Describe what the values of your custom styles are in styles.xml.
But you will need read more about the attrs.xml
<item name="android:background">? android:attr/activatedBackgroundIndicator</item>
</style>
Instead, we are referring to the value of some other attribute – activatedBackgroundIndicator – from our inherited theme. Whatever the theme defines as being the activatedBackgroundIndicator is what our background should be.

Categories

Resources