Android cascading layouts? - android

Is there a way to specify different styles for different elements of a view group within one style?
For example, I have a list where each item has a title, details and separator. I would like to be able to have one style tag in my styles.xml that applies side padding to the text but only top/bottom padding to the separator.
I realise my thinking could be influenced by css, I was just wondering if there was an elegant solution in android for it.

A style can have a parent, with the resulting view applying attributes "top-down", i.e. the child styles will override conflicting parent style attributes.
Code I ended up using (I have a list with multiple separators, I wanted padding only on the last one):
<style name="ListItemSeparator">
<item name="android:background">android:attr/listDivider</item>
<item name="android:layout_height">1px</item>
</style>
<style name="LastListItemSeparator" parent="ListItemSeparator">
<item name="android:layout_marginBottom">20dp</item>
</style>
More info can be found here

If it's just your own styles you want to extend, then you can use the dot notation, as mentioned in the Android docs, i.e. you could do:
<style name="ListItemSeparator">
<item name="android:background">?android:attr/listDivider</item>
<item name="android:layout_height">1px</item>
</style>
<style name="ListItemSeparator.LastListItemSeparator">
<item name="android:layout_marginBottom">20dp</item>
</style>
Then reference the style like:
<View style="#style/ListItemSeparator.LastListItemSeparator"/>

You can subclass a View in java and then refer to it in your xml.
Then, you can subclass your custom View to create views that inherit from it.

Related

Layout Attributes within Styles

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.

Defining styles in Android and need to be inheriting from a parent

I am a little confused about how I should be writing my styles.
I have written some styles and they appear to work great but I am unsure if I should be inheriting from a style.
For example, by default, a text view (for example) has a default style before applying mine?
So I should be inheriting from something else in my style before applying it, i.e. a halo style?
So, for example, I designed the following style
<style name="TestMe">
<item name="android:textSize">30sp</item>
<item name="android:textColor">#FFFF0000</item>
</style>
Which I have applied to a few text views, seems to work great but should I be doing
<style name="TestMe" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:textSize">30sp</item>
<item name="android:textColor">#FFFF0000</item>
</style>
Inheriting from a parent, if so which one?
If I apply a style to my text view and do not inherit, in effect is the text view losing a lot of styles that were predefined on it before applying my style? I know that I have an app theme that inherits from a parent and this is applied in the androidmanifest.xml. So adding a style doesn't override the theme, which in essence is a style?
Or is inheritance on styles only being used when I want to override something?
Be aware of the precedence order of different styling techniques — if you’re trying to style some text and not seeing the results you expect then your changes are likely being overridden by something higher up in this hierarchy:
Here the whole detail regarding text appearance URL

Set a consistent theme for all the editTexts in Android

I have finished making my app. Now, I want to reset all my editTexts to have the layout width as fill parent instead of wrap content.
android:layout_width="fill_parent"
while currently all my editTexts are
android:layout_width="wrap_content"
Is there any way i can do this in a style xml file, instead of individually in each layout?
I currently have this as my styles.xml
<style name="AppTheme" parent="android:Theme.Light">
<item name="android:fontFamily">Verdana</item>
<item name="android:editTextStyle">#style/EditTextStyle</item>
</style>
<style name="EditTextStyle" parent="#android:style/Widget.EditText">
<item name="android:layout_width">fill_parent</item>
<item name="android:textColor">#808080</item>
</style>
But i'm getting an exception saying that layout_width must be specified.
This is my exception:
07-15 11:13:34.872: E/AndroidRuntime(1195): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.passwordkeeper.ui/com.passwordkeeper.ui.ActivityLogin}: java.lang.RuntimeException: Binary XML file line #29: You must supply a layout_width attribute.
Any easy way out or do i have to change the attribute in all my editText's individually?
You can try this one.
Here is the part of the manifest file you need to change to call your custom theme (the custom theme called here is AppTheme:
<application android:name="YourApplication"
android:theme="#style/AppTheme" >
Then in your file styles.xml, create and customize this custom theme:
<style name="AppTheme" parent="#android:style/Theme.Holo.Light">
<item name="android:typeface">YourTypeFace</item>
</style>
You can add the parameters you need inside the style. This will apply the style to all your textviews.
One solution to your problem is to apply a custom theme to all of your activities. In order to do that, you can inherit properties from an existing theme and override the properties that you want to change.
In AndroidManifest.xml, locate the <application> element.
Add the attribute to it:
android:theme="#style/"
Locate styles.xml file in the values folder.
Use the following template:
<style name="ApplicationStyle" parent="android:Theme.Light">
<item name="#android:editTextStyle">#style/customEditText</item>"
</style>
Names used in the above are just examples, you may use your own. As to the parent theme, that is also up to you.
All that is left is the definition of editTextStyle (or whatever name you have chosen for the style). You should inherit properties from Widget.EditText and override the properties that you want to change, like the following:
<style name="customEditText" parent="#android:style/Widget.EditText">
<item name="android:textColor" >#ffffff</item>
</style>
To quote the official android guide:
The parent attribute in the element is optional and specifies
the resource ID of another style from which this style should inherit
properties. You can then override the inherited style properties if
you want to.
I tried to make it easy to understand and follow. I'm a junior dev so while the above solution works for me, it may not be the best one out there. As I said though, it solves the problem rather efficiently.
Unfortunately it is not possible to set layout attributes (layout_*) from a theme (see Layout Parameters documentation and this answer from an Android framework engineer). You must set them on each element or set the layout attributes in a style and let each element reference the style like this:
<Button style="#style/ButtonBig" android:text="my text" />
where ButtonBig is defined like this:
<style name="ButtonBig" parent="android:Widget.Holo.Light.Button">
<item name="android:textSize">20sp</item>
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">100dp</item>
</style>
I was having this exact issue. For some reason it helped me to drop the android: part in the AppTheme definition, and leave it only as editTextStyle (as mentioned in this answer):
<style name="AppTheme" parent="android:Theme.Light">
<item name="android:fontFamily">Verdana</item>
<item name="editTextStyle">#style/EditTextStyle</item>
</style>
You'll have to set the property style="#styles/EditTextStyle" to all of your EditText components in your application.
define the style attribute for all EditText like below:
<EditText
android:id="#+id/editText1"
android:layout_height="wrap_content"
style="#style/EditTextStyle">
You have to specify layout_width individually to each and every View. There is no way To escape. You can create a LayoutParams object and set its width and height in it and set in it every EditText like
textView1.setLayoutParams(lParams);
textView2.setLayoutParams(lParams);
...

android: How can I define custom colors, drawables, etc. in themes?

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 ...)

How to apply two different styles to one element in android?

I have a TextView and I want to apply a Style which I use for all TextView elements plus another style which I only use within a specific Activity. Is there any possibility to do that?
Just a little piece of information that might add to the overall value of the question - shamelessly copied from: http://developer.android.com/guide/topics/ui/themes.html#DefiningStyles
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. For example, to create a new style that inherits the CodeFont style defined above, but make the color red, you can author the new style like this:
<style name="CodeFont.Red">
<item name="android:textColor">#FF0000</item>
</style>
Notice that there is no parent attribute in the tag, but because the name attribute begins with the CodeFont style name (which is a style that you have created), this style inherits all style properties from that style. This style then overrides the android:textColor property to make the text red. You can reference this new style as #style/CodeFont.Red.
You can continue inheriting like this as many times as you'd like, by chaining names with periods. For example, you can extend CodeFont.Red to be bigger, with:
<style name="CodeFont.Red.Big">
<item name="android:textSize">30sp</item>
</style>
A style under Android can have a parent style.
So just have MyActivityTextView define GeneralTextView as parent style, and change/add style properties.
Then you can use MyActivityTextView for some views and GeneralTextView for the others.
It's described in Defining Styles.
You can extend one style with another in your style.xml:
<style name="current_weekday_white" parent="current_day_white">
<item name="android:textColor">#FFABAB</item>
</style>
Inherit one style from another and copy elements from third.
<style name="Button.Style1" parent="android:style/Widget.Button">
<item name="android:gravity">center</item>
<item name="android:textSize">12sp</item>
<item name="android:background">#drawable/shape_button</item>
<!-- Here are attributes from third style -->
<item name="android:fontFamily">sans-serif-medium</item>
<item name="android:textColor">#112233</item>
</style>

Categories

Resources