How to use Android styles inheritance with different qualifiers - android

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.

Related

How do I set the color of a Switch in Android API 21+

OK, I don't need nor want AppCompat stuff. This is for a ROM utility app, so I know exactly what API is supported (I literally control the whole system). I don't need anything below API 22 and I'm compiling to that API.
I want to know what I can add to my styles.xml to get the switch color to match the rest of the theme (#color/primary_color). Here is what I have ... (and some of this is likely un-necessary from testing too much at once).
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="android:Theme.Material.Light.DarkActionBar">
<item name="android:colorButtonNormal">#color/primary_color</item>
<item name="android:shadowColor">#android:color/black</item>
<item name="android:colorControlHighlight">#color/primary_color</item>
<item name="android:textViewStyle">#style/BlackText</item>
<item name="android:actionMenuTextColor">#color/hilight_color</item>
<item name="android:colorControlActivated">#color/primary_color</item>
<item name="android:colorPrimary">#color/blackness</item>
<item name="android:colorAccent">#color/primary_color</item>
</style>
<style name="BlackText">
<item name="android:textColor">#android:color/black</item>
</style>
</resources>
In xml layout:
<android.support.v7.widget.SwitchCompat
android:id="#+id/switch_subs"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#android:color/transparent"
android:button="#null"
android:padding="20dp"
android:theme="#style/ColorSwitchStyle" />
In styles.xml
<style name="ColorSwitchStyle">
<item name="colorControlActivated">#color/colorPrimary</item>
</style>
*** in my case colorPrimary is blue.

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>

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.

Applying custom styles to Android SpinnerItems

This question has been asked before, but carefully studying the answers on previous posts hasn't helped me decipher the problem.
I'm trying to apply custom styles to the items in a spinner control in my Android app, using a custom theme. I can't get the spinner items to respect the custom styles.
Here's what I have in themes.xml:
<resources>
<style name="CustomTheme" parent="android:Theme">
<item name="android:spinnerItemStyle">#style/CustomSpinnerItem</item>
<item name="android:windowTitleSize">25dp</item> <!-- This works -->
</style>
</resources>
And here's my styles.xml:
<resources>
<style name="CustomSpinnerItem" parent="android:Widget.TextView.SpinnerItem">
<item name="android:textAppearance">#style/CustomTextAppearanceSpinnerItem</item>
<item name="android:padding">20dp</item> <!-- This works fine -->
</style>
<style name="CustomTextAppearanceSpinnerItem" parent="android:TextAppearance.Widget.TextView.SpinnerItem">
<item name="android:textColor">#F00</item> <!-- This does NOT work -->
</style>
</resources>
Note the comments about what's working and what isn't. I'm pretty sure the problem is in the CustomTextAppearanceSpinnerItem section, but I'm at a loss as to what's wrong.
Any suggestions?
This works well for me
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="MySpinnerItem" parent="#android:Widget.TextView.SpinnerItem">
<item name="android:textAppearance">#style/MySpinnerTextAppearance</item>
</style>
<style name="MySpinnerTextAppearance" parent="#android:TextAppearance.Widget.TextView.SpinnerItem">
<item name="android:textColor">#FF0000</item>
</style>
</resources>

Categories

Resources