Android Use custom themes to modify style attributes - android

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>

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 default button styling not working

I'm trying to set up my styles to make all buttons a particular color combination, specifically blue with white text. Here's my main styles.xml:
<resources>
<style name="CustomTheme" parent="MaterialDrawerTheme.Light.DarkToolbar">
<!-- various items -->
<item name="android:buttonStyle">#style/ButtonStyle</item>
</style>
<!-- a couple of other styles -->
<style name="ButtonStyle" parent="android:style/Widget.Button">
<item name="android:textSize">19sp</item>
<item name="android:textColor">#color/primaryTextContrast</item>
<item name="android:background">#color/primary</item>
</style>
</resources>
And in the manifest:
<application
android:name=".CustomApplication"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/application_name"
android:theme="#style/CustomTheme">
color/primary is dark blue, and color/primaryTextContrast is white. On Lollipop, the button looks perfect. On a 4.1 device, it's light gray with black text. Every resource I've found for doing this looks exactly like what I'm doing so I don't know what I'm missing here.
I'm having a similar issue with controlling text size in the base style definition as well.
Update: here are the colors.
<resources>
<color name="primary">#3F51B5</color>
<color name="dark">#303F9F</color>
<color name="accent">#FFCA28</color>
<color name="background">#android:color/white</color>
<!-- Color for text displayed on top of the primary or dark color -->
<color name="primaryTextContrast">#android:color/white</color>
<!-- Color for text displayed on the background color (which I think will always be white) -->
<color name="basicText">#color/primary</color>
<!-- Color for text displayed on the accent color -->
<color name="accentText">#303F9F</color>
</resources>
Here's v19/styles.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="FullscreenTheme" parent="MaterialDrawerTheme.Light.DarkToolbar.TranslucentStatus">
<item name="android:windowTranslucentNavigation">true</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowTranslucentStatus">true</item>
</style>
</resources>
Here's v21:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="CustomTheme">
<item name="android:windowContentTransitions">true</item>
<item name="android:windowAllowEnterTransitionOverlap">true</item>
<item name="android:windowAllowReturnTransitionOverlap">true</item>
<item name="android:windowSharedElementEnterTransition">#android:transition/move</item>
<item name="android:windowSharedElementExitTransition">#android:transition/move</item>
</style>
</resources>
I don't think either of these is what's making it work properly on 5.1.
Using AppCompat 22.1.+ (22.2.0 should work too), I defined a Style like this:
<style name="MyApp.Button.Red" parent="Base.Widget.AppCompat.Button">
<item name="colorButtonNormal">#color/primary</item>
<item name="android:colorButtonNormal">#color/primary</item>
<item name="android:textColor">#android:color/white</item>
</style>
and then applied the theme in a button using the native theme attribute from android namespace, as said in this awesome post from Chris Banes.
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/sign_up_button"
android:theme="#style/MyApp.Button.Red" />
I tried adding buttonStyle without the android: prefix and it solved the problem. Yeah, weird.
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="buttonStyle">#style/ButtonStyle</item>
<item name="android:buttonStyle">#style/ButtonStyle</item>
</style>
gradle:compile 'com.android.support:appcompat-v7:22.2.0'
For theme to work properly in android lollipop, you need to extend
ActionBarActivityinstead of Activity.
By doing this change,your theme setting should work properly.
This is general for other people that for lower version of android,you should not use android: tag in item-name definition
`

Themes in Android are mixing

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

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.

Android apply style to custom TextView

I have a class, TextViewStyled, which extends TextView
In my theme XML, how do I apply a style to all my TextViewStyled widgets on Activities with a chosen theme?
I have this simple theme, but I want to limit the Black Gold style to TextViewStyled Widgets without specifying the Black Gold in the TextViewStyled style attribute. This is one of many themes which will be switched dynamically.:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="MyThemeOneofMany" parent="android:Theme.NoTitleBar.Fullscreen">
<item name="android:???????????">#style/TextViewStyled_Black_Gold</item>
</style>
<style name="TextViewStyled_Black_Gold" parent="#android:style/Widget.TextView">
<item name="android:background">#1E1921</item>
<item name="android:textColor">#A85E4F</item>
<item name="android:textColorLink">#FFBC4F</item>
<item name="android:textStyle">normal</item>
</style>
</resources>
For AppCompat theme (2.3.3+):
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="android:textViewStyle">#style/PizzaSizeWidget</item>
</style>
<style name="CustomTextView" parent="#android:style/TextAppearance.Widget.TextView">
<item name="android:background">#1E1921</item>
<item name="android:textColor">#A85E4F</item>
<item name="android:textStyle">normal</item>
<item name="android:textSize">93sp</item>
</style>
In order to set the style for TextViews in your custom Theme use the name "android:textViewStyle":
<style name="MyThemeOneofMany" parent="android:Theme.NoTitleBar.Fullscreen">
<item name="android:textViewStyle">#style/TextViewStyled_Black_Gold</item>
</style>
Found it when looking through the official android themes.xml [click].
I found that updating the styles works when overriding the base textview class after the inflation event.

Categories

Resources