This theme works fine, referencing three custom styles for the 3 parts of the ActionBar's tabs.
But the "dividerPadding" has no effect on any of them - running on API 17 devices.
<style name="Theme.AppEmptyTitleBar" parent="android:style/Theme.Holo">
<item name="android:actionBarStyle">#style/AB</item>
<item name="android:actionBarTabStyle">#style/ABT</item>
<item name="android:actionBarTabBarStyle">#style/ABTB</item>
</style>
<style name="AB" parent="android:style/Widget.Holo.ActionBar">
<item name="android:dividerPadding">20dip</item>
</style>
<style name="ABT" parent="android:style/Widget.Holo.Light.ActionBar.TabView">
<item name="android:dividerPadding">20dip</item>
</style>
<style name="ABTB" parent="android:style/Widget.Holo.ActionBar.TabBar">
<item name="android:dividerPadding">20dip</item>
</style>
First of all, the dividerPadding attribute is (as far as I know) only applicable to the *ActionBar.TabBar style.
I've tested your style using a very basic application making use of the native ActionBar and a device providing API 17. I've set the dividerPadding attribute to different values and left the rest of the attributes with default values. Here are the results:
dividerPadding="0dip":
dividerPadding="15dip":
dividerPadding="20dip":
As you can see, divider is gone on the last image. So my first advice would be to check if you see it at all. Other than that, the dividerPadding seems to be working as expected.
My second advice comes from the way Android platform handles style resources placed in different values-* directories. My hunch is that you might be making use of your action bar styles in the default values directory. If you then happen to provide an override of these styles in a values-* directory which is compatible (e.g. values-vX where X <= 17), the styles from values will be ignored. As an example, consider that you've placed these sample styles in the values/styles.xml file:
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="AppTheme" parent="#android:style/Theme.Holo">
<item name="android:actionBarTabBarStyle">#style/ABTB</item>
</style>
<style name="ABTB" parent="#android:style/Widget.Holo.ActionBar.TabBar">
<item name="android:dividerPadding">0dip</item>
</style>
</resources>
If you then place this style definition in values-v17/styles.xml:
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="AppTheme" parent="#android:style/Theme.Holo">
</style>
</resources>
it will override the AppTheme style, effectively "resetting" (technically: ignoring) the whole actionBarTabBarStyle style (including the dividerPadding attribute value). In effect, you won't see any changes made to the ABTB style.
Edit
Yup, I assumed you know that, sorry :( The dividerPadding value applies only to:
Top and bottom of divider when the TabWidget (it's the container of tab labels) draws tabs horizontally.
Left and right sides of divider when the TabWidget draws tabs vertically.
Which is exactly what you see in the screenshots. As far as I know, you have to set divider to a drawable which will force additional padding. I believe the layer drawable will be great for that purpose because you can set padding explicitly for every layer.
Related
I've been with a dilemma for a while that I don't know how to solve it properly. I want to use DRY (Don't Repeat Yourself), but not apply bad practices in styles (such as set the layout attributes inside them).
This is my case...
To have the text styles encapsulated in my projects, I usually use the following:
I have a style called Wrap_Content
<style name="WrapContent">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
</style>
On the one hand, I have a style called Tv that inherits from WrapContent:
<style name="Tv" parent="WrapContent">
<item name="android:fontFamily">#font/font_foo</item>
<item name="android:textColor">#color/color_foo</item>
</style>
As you can see, apart, the Tv style has a default font and text color
If for example I want to use a font size of 15sp, I apply this style:
<style name="Tv.15">
<item name="android:textSize">15sp</item>
</style>
And so on...
Well, the issue is that all the TextView of my project I set wrap_content both width and height.
Therefore, doing things like this simplifies the layouts XML a lot and it increases the readability and grouping common behaviors.
Example:
<TextView
style="#style/Tv.15"
android:text="#string/foo"/>
And if in any case, I want to change any attribute, I have only to overwrite it from where I call it.
The dilemma is that I am mixing textAppearance styles with layout ones. I have thought about separating this ... but I have not just resolved the main issue, that I am setting layout attributes on it, something that I should know nothing more than its own view, and not its container.
But what does not convince me at all is to do something like this:
<style name="Tv">
<item name="android:fontFamily">#font/font_foo</item>
<item name="android:textColor">#color/color_foo</item>
</style>
<style name="Tv.15">
<item name="android:textSize">15sp</item>
</style>
<TextView
style="#style/Tv.15"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/foo"/>
I don't want to repeat a million times with the same attributes if these are common. Or yes I see what it brings ... technical debt. Therefore, it does not seem like a valid option.
I have searched quite a lot and the truth is that I have not found anything that convinces me and I would like to reach something elegant, since it is something that I use at all times and I don't like it.
Well... what do you think about it?
Thank you so much!!!
EDITED 2019-11-08
I have thought a new approach adding a new layer of styles, the #style/TextAppearance. It is like this:
<style name="WrapContent">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
</style>
<style name="TextAppearance">
<item name="android:fontFamily">#font/font_foo</item>
<item name="android:textColor">#color/color_foo</item>
</style>
<style name="TextAppearance.15">
<item name="android:textSize">15sp</item>
</style>
<style name="Tv" parent="WrapContent">
<item name="android:textAppearance">#style/TextAppearance</item>
</style>
<style name="Tv.15">
<item name="android:textAppearance">#style/TextAppearance.15</item>
</style>
This add a little bit of complexity to the system, but it splits the layout and the textAppearance attributes. Moreover, it allows use the TextAppearance style for buttons, editTexts an so on.
In our most recent Android Dev Summit, two of my colleagues gave a talk on how to use Theme & Style. We advice that you use Themes for View groups and their children and styles for simpler views. Perhaps your layout needs can be met by using Themes and then reserving styles for text appearances and such. Beyond that, efficacy should guide how you structure your style objects.
I know I can add different XMLs for different API levels, for example having different styles for values-v21 and values-v19. What I'm trying to understand is how the build system actually works with those different values? So for example if I have the bulk of my styles common across all APIs and one item of one style changes between 21 and the rest, do I:
1) Copy the whole styles.xml into v21 and change the one value I need to change
2) Only add that one style that changed to styles.xml under v21
3) Only add that one item of that one style that changed under 21
It's confusing and I couldn't find any documentation how the built process handles merging styles.
Rules are quite clear:
While running Android selects the best-matching style
If selected style is a child style, Android merges its items with parent best-matching style
If you provide your mutable item via a reference, just define its value to match selected api version.
<style name="SomeStyle">
<item name="someColor">#color/some_color</item>
</style>
You can have some_color.xml in color-v21 folder for API 21 and a common version of this file in a color folder for all other api levels.
Example:
You want to have the following style for non-v21 API
<style name="FinalStyle">
<item name="commonText">It\'s a common text</item>
<item name="specificDrawable">#drawable/icon</item>
<item name="specificColor">#color/primary_color</item>
<item name="specificText">non-v21</item>
</style>
And the following style for v21 API
<style name="FinalStyle">
<item name="commonText">It\'s a common text</item>
<item name="specificDrawable">#drawable/icon</item>
<item name="specificColor">#color/secondary_color</item>
<item name="specificText">v21</item>
</style>
Specific-parameters differ between v21/non-v21 API, common parameters are common.
How to do it?
res/values/styles.xml
<style name="BaseStyle">
<item name="commonText">It\'s a common text</item>
<item name="specificDrawable">#drawable/icon</item>
</style>
<style name="FinalStyle" parent="BaseStyle">
<item name="specificColor">#color/primary_color</item>
<item name="specificText">non-v21</item>
</style>
res/values-v21/styles.xml
<style name="FinalStyle" parent="BaseStyle">
<item name="specificColor">#color/secondary_color</item>
<item name="specificText">v21</item>
</style>
res/drawable/icon.png
Common icon
res/drawable-v21/icon.png
v21 icon
When Android searches FinalStyle for v21, it selects FinalStyle definition from res/values-v21 as best-matching style, and merges with BaseStyle. In this example there is also another best-matching resource search, when Android searches #drawable/icon.
This is for anyone who comes across this and is still just as confused as I was, even after a lot of reading and trial & error. Hopefully this helps.
The folder structure is like #Dmitry stated.
res/values/styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
<style name="AppBase" parent="Theme.MaterialComponents.NoActionBar">
<!-- simple: overrides colorPrimary in parent theme -->
<item name="colorPrimary">#color/brand_blue</item>
<item name="colorSecondary">#color/brand_grey</item>
<!-- sets the attributes in materialButtonStyle with style: myMaterialButton -->
<!-- the materialButtonStyle attribute is what actually changes the button settings -->
<item name="materialButtonStyle">#style/myMaterialButton</item>
</style>
<!-- this style consists of common 'attributes' among all API versions -->
<!-- you can choose to add a parent to inherit an additional style -->
<!-- unlike the materialButtonStyle attribute, this parent is not necessary to change the button settings -->
<style name="myMaterialButton" parent="Widget.MaterialComponents.Button">
<item name="cornerRadius">60dp</item>
<item name="android:paddingVertical" tools:targetApi="26">20dp</item>
</style>
<!-- this will add on and override AppBase and should include any changes that differ from other API versions -->
<style name="AppBaseChanges" parent="AppBase">
<!-- to inherit myMaterialButton, you don't have to include it in here, since it's in AppBase -->
<!-- however, if you want to extend myMaterialButton, create a new style as its child -->
<item name="materialButtonStyle">#style/myMaterialButtonAPI_All</item>
</style>
<!-- make sure the parent is myMaterialButton to inherit/override its settings -->
<!-- this will be picked for all APIs lower than other styles like this -->
<style name="myMaterialButtonAPI_All" parent="myMaterialButton">
<item name="backgroundTint">?attr/colorPrimary</item>
</style>
</resources>
res/values-v2/styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- restate the same declaration as the other xml file-->
<style name="AppBaseChanges" parent="AppBase">
<!-- use a different name (...API_2) for the overriding style -->
<item name="materialButtonStyle">#style/myMaterialButtonAPI_2</item>
</style>
<style name="myMaterialButtonAPI_2" parent="myMaterialButton">
<item name="backgroundTint">?attr/colorSecondary</item>
</style>
</resources>
Set the manifest theme to AppBaseChanges. The app will pick only one AppBaseChanges style to apply changes, so be sure to carefully override the right styles to ensure you are inheriting from lower level versions.
For some reason, AndroidStudio doesn't do a good job at all previewing themes, so before you think it's not working, relaunch the app to see the changes. There are also situations where I have no idea why it wasn't updating the setting and couldn't find where it was overriding the theme. In those cases you can dig further, or avoid the hassle and just apply the relevant style directly to the view.
Here's the order of precedence for the sample themes described above. The higher the style, the higher precedence it has and will override the lower style.
either myMaterialButtonAPI_All or myMaterialButtonAPI_2
AppBaseChanges (only one is chosen)
myMaterialButton
Widget.MaterialComponents.Button
AppBase
Theme.MaterialComponents.NoActionBar
You may maintain only one styles.xml(default) file for all the device version.
Checkout my answer to How to remove repeating of similar styles in v19/styles.xml and v21/styles.xml files
https://stackoverflow.com/a/53445541/5745574
I want to set item elevation in some of my app's styles. Now elevation is only 21 and higher with no support library, so my natural inclination was to just create a styles-v21 xml and place it in there:
<style name="Widget.MyApp.Drawer" parent="ThemeOverlay.AppCompat.Dark.ActionBar">
<item name="android:elevation">4dp</item>
</style>
The problem with this is any changes I make to Widget.MyApp.Drawer in the regular styles.xml file will be overwritten by this completely. What I'd want is for elevation to just be tacked on to the bottom of the list of style changes I made for the v21 version of this style listed in styles.xml.
So I took to creating base styles which the style I use in the views inherits from:
<style name="BaseListElement">
<item name="android:background">#drawable/listitem_background</item>
<item name="android:layout_height">#dimen/list_item_height</item>
</style>
<style name="BaseListElement.ListItem">
</style>
I leave the style blank in styles.xml, and in styles-v21, I add elevation and it works.
However this get's kind of tricky when I want to use some advanced styles:
<style name="BaseListElement">
<item name="android:background">#drawable/listitem_background</item>
<item name="android:layout_height">#dimen/list_item_height</item>
</style>
<style name="BaseListElement.BaseItem">
<item name="android:padding">#dimen/list_item_padding</item>
</style>
<style name="Widget.MyApp.ListItem" parent="#style/BaseListElement.BaseItem">
</style>
<style name="BaseListElement.BaseHeader">
</style>
In this case, BaseItem is just one style that inherits from BaseListElement, styles such as BaseHeader inherit from it as well. This is getting kind of ridiculous as you can see.
Am I overthinking this? The way I see it I have 3 choices here:
1) Continue as is and feel like an idiot
2) On the BaseListElement level, create a child style with some goofy name which is the point at which I apply the elevation, which would then (hopefully) trickle down to all the children. As soon as I have a difference between v21 children of the base however, this wouldn't work.
3) Just throw android:elevation into the styles.xml file (don't use a v21 file) and place an ignore flag on the element. I only have 5.0 devices here, so I can't easily test at the moment if this will cause a crash on older versions.
Any thoughts?
To accomplish something like this you could just create a BaseListElement.BaseItem in both styles.xml and syles-v21.xml the first one without the elevation and the second one with it. Then just extend Widget.MyApp.ListItem from BaseListElement.BaseItem which should get updated in v21 to use the elevation.
styles.xml
<style name="BaseListElement.BaseItem">
</style>
<style name="Widget.MyApp.ListItem" parent="#style/BaseListElement.BaseItem">
</style>
styles-v21.xml
<style name="BaseListElement.BaseItem">
<item name="android:padding">#dimen/list_item_padding</item>
</style>
Method 3 you can safely implement as follows:
<item name="android:elevation" tools:ignore="NewApi">4dp</item>
I'm trying to put a style in all my app, so i created a theme with my style inside :
<resources>
<style name="MyTheme" parent="android:Theme.Holo.Light">
<item name="android:textAppearance">#style/subtitle</item>
</style>
<style name="subtitle parent="#android:style/TextAppearance">
<item name="android:textColor">#color/purple</item>
<item name="android:textSize">40sp</item>
</style>
</resources>
But textAppearance doesn't work it stay the same, but when i put something like textColor in my theme, it works
This is a quite old question, but the answer may help someone.
The key to solve this is in the "precedence order of styling techniques" here:
on the top is the highest precedence, at the bottom is the lowest precedence.
As we can see theme has the lowest precedence, in your example, your android:textAppearance property is being overridden by the default style of every view that accepts this attribute, the default style property is defined in every them for every specific view that accepts this attribute, in this case android:Theme.Holo.Light provides the default style for textView as android:textViewStyle... for buttons is android:buttonStyle (which inherits its textAppearance from TextView), and so on.
So if you are trying to apply that android:textAppearance property to a TextVew you should use <item name="android:textViewStyle">#style/subtitle</item> instead of <item name="android:textAppearance">#style/subtitle</item> inside MyTheme. Away to veryfy this is setting android:textViewStyle to null, that way your current code will work fine with textViews <item name="android:textViewStyle">null</item>
This post explains this precedence a bit deeper:
https://medium.com/androiddevelopers/whats-your-text-s-appearance-f3a1729192d
What I can see is, you have not declared the color in your xml for theme. Please add the following line within the <resources> and try. Your xml will look like:
<resources>
<style name="MyTheme" parent="android:Theme.Holo.Light">
<item name="android:textAppearance">#style/subtitle</item>
</style>
<color name="purple">code for your color</color>
<style name="subtitle parent="#android:style/TextAppearance">
<item name="android:textColor">#color/purple</item>
<item name="android:textSize">40sp</item>
</style>
I think this will do.
Depends on your target API you need to put your customization code in different /res/values-vxx/style.xml files.
For TextView, try android:textAppearanceSmall inside your theme instead.
I hope I can explain what I'm after. In essence, my users have asked me to allow different looks in my application, which I hope I can do with themes.
I hoped I could do something like this:
<style name="NewTheme" parent="android:Theme.Dark">
<item name="labelColor">#f90</item>
<item name="buttonColor">#fff</item>
<item name="buttonBg">#drawable/button</item>
</style>
<style name="OldTheme" parent="android:Theme.Dark">
<item name="labelColor">#fa0</item>
<item name="buttonColor">#88f</item>
<item name="buttonBg">#drawable/button_old</item>
</style>
And then reference these values in my styles.xml:
<style name="labelStyle">
<item name="android:textColor>#labelColor</item>
</style>
<style name="buttonStyle">
<item name="android:textcolor">#buttonColor</item>
<item name="android:background">#buttonBg</item>
</style>
I know this syntax is wrong, but what might be the right syntax? Basically, I want to create sets of attributes (color, background, a couple other things) and select them based on theme.
To work with themes and styles in Android you have to:
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.
In your layout files, give your views a style attribute, which has a
custom style name as their values.
Set the theme of your application or activity in either
AndroidManifest.xml or in the Activity's onCreate(). This is done by calling setTheme() in the activity's onCreate() method, before any call to setContentView().
To change the theme, you simply need to restart your activity.
Iadvice you to look at this tutorial it deals with all that a programmer want to work on android themes (text color, text formatting, state list drawable etc ...)