Reuse TextView code in Android XML - android

I'm making out a few menus for my Android App and throughout there is a standard textview that is repeated 5 times, only changing the android:text tag each time, everything else is the same.
There are a good number of properties on this and it feels very inefficient to be copy/pasting all these for each of the textviews.
Is there a way I define the common properties just once and add them to each TextView element?

Yes you can define a style. Create a file in your values res folder names styles.xml and add something like this:
<resources>
<style name="my_header_text">
<item name="android:textStyle">bold</item>
<item name="android:textSize">18sp</item>
<item name="android:textColor">#android:color/white</item>
</style>
</resources>
This defines the style. In your layout you might have a field like this:
<TextView
android:id="#+id/my_title"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
style="#style/my_header_text"
android:layout_centerVertical="true"
android:layout_marginLeft="5dip"/>
Notice the style statement refers to the style defined above. Styles can contain almost any property. Read up on them here.

Related

How does an android:attr style work?

I'm trying to build an Android UI via layouts. I start with the following:
<TextView
android:id="#+id/..."
android:layout_marginTop="8dip"
android:text="..."
style="?android:attr/listSeparatorTextViewStyle"/>
And that looks good (all caps, smaller font, dividing bar underneath it). Now I want to extend the style, so I change it to the following:
<TextView
android:id="#+id/..."
android:layout_marginTop="8dip"
android:text="..."
style="#style/section_title"/>
With a style of:
<style name="section_title" parent="#android:attr/listSeparatorTextViewStyle">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
</style>
And that doesn't work (font is correct, but the divider line is gone).
How come... that?
When you're using:
style="?android:attr/listSeparatorTextViewStyle"
you're using the style pointed by this attribute(listSeparatorTextViewStyle). If you look in the platform themes.xml you'll see that the style that is actually used for this attribute is Widget.TextView.ListSeparator.White. So this is the style you should extend in your custom style.
Unfortunately that style is private and you can't extend it, or you shouldn't extend it(for reference, see this bug report from google). Your best option would be to copy that entire style, Widget.TextView.ListSeparator.White(Widget.TextView.ListSeparator isn't public as well so would have to also copy that), in your custom style and use that instead of extending the style from the android platform(see this response from the link above).

Android - use attributes to tweak custom styles

here's my issue. I have defined custom themes and styles, so as to customize various Views, in the relevant .xml files. Here are some code extracts:
themes.xml:
...
<style name="Legacy" parent="android:Theme.NoTitleBar">
<item name="android:buttonStyle">#style/Legacy.Button</item>
...
</style>
styles.xml:
...
<style name="Legacy.Button" parent="#android:style/Widget.Button">
<item name="android:textColor">#ffffff</item>
<item name="android:background">#drawable/button_selector_blue</item>
<item name="android:textSize">15dp</item>
</style>
Let's say I set my application's theme to Legacy. If I use a Button in a layout, it will get my custom default parameters (white text, background is #drawable/button_selector_blue, etc).
Now let's say I want to keep those parameters save for the text size: I'd like to have some buttons with a larger text size, which would be defined in an titleSize attribute in attrs.xml:
...
<attr name="titleSize" format="reference|dimension" />
and which value is set for each theme in my themes.xml file.
So my layout would contain something like:
<Button
android:id="#+idmyButtonId"
android:drawableRight="#drawable/aDrawable"
android:text="#string/someText"
android:textSize="?titleSize"
android:layout_width="fill_parent" android:layout_height="wrap_content">
</Button>
When launching my app I get the following error:
java.lang.UnsupportedOperationException: Can't convert to dimension: type=0x2
So it seems I cannot tweak custom styles using attributes - at least not this way. Is such a thing possible ? If not, what would you use to achieve such a result ?
I'd like to give the user the ability to select among different themes, so I can't just define an additionnal ButtonWithLargeText style and directly use it in my layout.
Thanks for your help !
I finally got it to work. Instead of defining my titles' size in attrs.xml, I used dimens.xml. So now the following works:
<Button
android:id="#+idmyButtonId"
android:drawableRight="#drawable/aDrawable"
android:text="#string/someText"
android:textSize="#dimen/titleSize"
android:layout_width="fill_parent" android:layout_height="wrap_content">
</Button>
While I get my regular text size (which I defined in my styles.xml) on the Button by using this:
<Button
android:id="#+id/idRegularButton"
android:text="#string/regularSizeText"
android:layout_width="wrap_content" android:layout_height="wrap_content">
</Button>

Different formats for different Textview defined by Custom style

I have a problem figuring out how to do this:
I am currently coding an app that comes with different themes (User can select the complete appereance of the app out of a list of different styles).
Then the list item is selected I want to call setTheme(R.style.Own_App_Style0); to change the complete appearance.
The problem is best explained by an example:
Lets say we have 2 TextView.
Theme1
1. TextView: TextColor should be green and TextSize 15sp.
2. TextView: TextColor should be red and TextSize 10sp.
Theme2
1. TextView: TextColor should be blue and TextSize 10sp.
2. TextView: TextColor should be yellow and TextSize 10sp.
Of course I know that by setting <item name="textViewStyle">#android:style/Widget.TextView</item> I can change the default appearance of TextViews.
But how can it be done to have lets say two (ore more) different types of TextView with different applied styles (and by xml)?
Found a solution (basically in this answer setTextAppearance through code referencing custom attribute). In case anyone else has this problem I shortly explain:
Declare in style.xml a attribute and in the actual style definition asign a value (reference) to this attribute:
<declare-styleable name="CustomTextView">
<attr name="mainTextView" format="reference"/>
</declare-styleable>
<style name="appstyle0" parent="android:style/Theme.Holo.Light">
<item name="#attr/mainTextView">#style/CustomTextViewAppearance1</item>
<item name="android:textViewStyle">#style/CustomTextViewAppearance2</item>
</style>
<style name="appstyle1" parent="android:style/Theme.Holo.Light">
<item name="#attr/mainTextView">#style/CustomTextViewAppearance2</item>
<item name="android:textViewStyle">#style/CustomTextViewAppearance1</item>
</style>
<style name="CustomTextViewAppearance1">
<item name="android:textSize">10dip</item>
</style>
<style name="CustomTextViewAppearance2">
<item name="android:textSize">30dip</item>
</style>
Now in the layout all textViews are like CustomTextViewAppearance2 (because this is set as standard in this style. And the textViews that should use the other style write into the definition:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="blablabla"
style="?mainButtonTextView"/>
When you now call .setTheme (after restart the activity) the appearance of the textviews switch. Like this method you can define as many different types of View styles and switch between them only by calling .setTheme.
Unfortunately, styles are static once they are defined. To have an entire cascade of styles modified programmatically, you would have to change the definition of the style itself. Instead, all you can do is change the style that is assigned to a TextView (or whatever style-able object), as outlined in the question I linked to in my comment above.

In Android XML, can I set buttonStyleSmall or Button.Small as a parent style to a custom style?

I want to extend Android's small button style. I can do it inline:
<Button android:id="#+id/myButton"
style="?android:attr/buttonStyleSmall"
android:layout_alignParentRight="true"
android:layout_gravity="right"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:textSize="10dp"
android:text="Click Here"/>
But in the interest of reusability, I want to transfer these styles to a custom style. How can I add buttonStyleSmall (or Widget.Button.Small?) as a parent to a style? Something like this in my custom style XML:
<style name="RightLink" parent="?android:attr/buttonStyleSmall">
<item name="android:layout_alignParentRight">true</item>
<item name="android:layout_gravity">right</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:paddingLeft">2dp</item>
<item name="android:paddingRight">2dp</item>
<item name="android:textSize">10dp</item>
</style>
with the button declaration using that style:
<Button android:id="#+id/myButton"
style="#style/RightLink"
android:text="Click Here"/>
EDIT
Using the correct syntax as described by Lukas below (use #android:attr/buttonStyleSmall as the parent), I'm still seeing a difference between the two:
Button with buttonStyleSmall as style and inline styles added:
Custom style with buttonStyleSmall as the parent:
What am I missing?
So you try to inherit style informations from a standard Android style. For this, you'll need to use the parent-attribute as you already did.
The only exception when inheriting a standard style is, that you have to use an # not a ?:
<style name="RightLink" parent="#android:attr/buttonStyleSmall">
A little more about how to do that for platform styles (because that differs from styles you created yourself) can be found here.
After playing around with it i found that the way you inhirate is correct, but the recourse is wrong:
<style name="RightLink" parent="#android:style/Widget.Button.Small">
This works.
The difference seams to be that the integer-constant which is used to add this by using the style-attribute and in code is declared in Androids R-class in the attr-subclass.
The XML-Style definitions (from which you can actually inherit) are stored in the style-subclass of the R-class. So the above line should solve your problem.

How do I cascade a style by theme in android

Basically, I'd like to have a single layout that I can skin differently on the theme. Many examples and entries on this site seem dance around the issue a little so I'm not entirely certain it can be done. Or I just don't get it.
Here's the concept.
Let's say my app is sports-related.. the app has a default them of 'SportTheme'
I'd like users also to say they want the 'Football' or 'Baseball' theme, and on designated <TextView> elements, I'd like the text (defaults to 'Sport') to change to 'Football' or 'Baseball' given the overall theme applied to the activity?
in strings.xml
<string name="label_sport">Sport</string>
<string name="label_football">Football</string>
<string name="label_baseball">Baseball</string>
in activityA.java - The important thing here is that the theme is set for the activity (or application is fine, too).
#Override
protected void onCreate(Bundle savedInstanceState)
{
Log.d(TAG, "onCreate");
super.onCreate(savedInstanceState);
this.setContentView(R.layout.layout_a);
switch (user.ThemePreference)
{
case FOOTBALL_THEME:
this.setTheme(R.style.FootballTheme);
break;
case BASEBALL_THEME:
this.setTheme(R.style.BaseballTheme);
break;
default:
this.setTheme(R.style.SportTheme);
break;
}
}
in layout_a.xml
...
<TextView
android:id="#+id/tvSport"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="#string/label_sport"
android:style="#style/SportLabel"></TextView>
What do I do in themes/styles? Something like this? The important thing here is the text in the TextView. I'll be using the same textView in several different activities throughout the application.
<theme name="SportTheme" parent="android:Theme" />
<theme name="FootballTheme" parent="SportTheme">
<item name="android:background">#color/brown</item>
</theme>
<theme name="BaseballTheme" parent="SportTheme">
<item name="android:background">#color/green</item>
</theme>
<theme name="SportTheme.SportLabel">
<item name="android:text">#string/label_sport</item>
</theme>
<theme name="FootballTheme.SportLabel">
<item name="android:text">#string/label_football</item>
<item name="android:textColor">#color/black</item>
</theme>
<theme name="BaseBallTheme.SportLabel">
<item name="android:text">#string/label_baseball</item>
<item name="android:textColor">#color/white</item>
</theme>
Thanks for any insight you can provide
To customize your UI with themes you need to define attributes you want to customize inside your themes and use references to these attributes in layouts (e.g. attr/backgroundColor).
There're three files in Android sources which are used for this purpose: attrs.xml, styles.xml and themes.xml. If you need some custom attributes for customization then you should declare them in attrs.xml. If you're going to use only predefined Android attributes then you don't need to create this file.
<declare-styleable name="SportTheme">
<attr name="customAttribute" format="color" />
<attr name="sportLabelStyle" format="reference" />
</declare-styleable>
The styles.xml file is used for defining sets of attribute values. For example you can define different style sets for each widget.
<style name="Widget.TextView.SportLabel" parent="#android:style/Widget.TextView">
<item name="android:textColor">#android:color/white</item>
<item name="android:textSize">20sp</item>
</style>
The themes.xml is the main file used for customizing. All themes are usually defined in this file. You can customize something in several ways. For example you can define a default value in the theme and reference it from a layout. Also you can define a reference to a style.
<style name="Theme.FootballTheme" parent="#android:style/Theme">
<!-- define value for predefined Android attribute -->
<item name="android:colorBackground">#android:color/white</item>
<!-- define value for custom attribute -->
<item name="customAttribute">#android:color/black</item>
<!-- define reference to a style -->
<item name="sportLabelStyle">#style/Widget.TextView.SportLabel</item>
</style>
layout.xml
<TextView
android:background="?android:attr/colorBackground"
android:textColor="?attr/customAttribute"
style="?attr/sportLabelStyle" />
Notice that style is used without the android namespace. That's not a typo.
So if you want to customize your layout using themes you can create several themes and define default values for attributes and attribute sets (styles) and reference these values using
?[android:]attr/attributeName
Sounds difficult but it's not really. You can use Android resources as an example of styling.
Please ask your question if something is not clear.
I have written a blog post about Themes which may help you. There is also a series of article on Custom Controls which explains how to create a custom control which is themeable, and this provides additional information about how Android themes work.

Categories

Resources