Reputation: 25601
I have an app with a customizable theme. The user can currently switch between 3 themes, which each change the background color, font color and font for the main display area, but not buttons or other widgets. Since there isn't a really good way to specify custom fonts in a theme, my application code is switching the typeface (using Typeface.CreateFromAsset
and TextView.Typeface
) in parallel with resetting the theme (using SetTheme
). (I believe the non-Xamarin version of these are Typeface.createFromAsset
, TextView.setTypeface
and setTheme
, BTW.) But I noticed that the fancy font looked smaller compared to the others, so whenever I use that theme I want the font to be bigger. So I created the following theme that inherits from my main theme:
<style name="Theme.StoryvoqueFancy" parent="@style/Theme.StoryvoqueLight">
<item name="android:textSize">18sp</item>
<item name="android:lineSpacingExtra">5sp</item>
<item name="android:textColorTertiary">#000000</item>
</style>
The textSize attribute accomplishes what I want it to with the main text, making it larger. What I can't figure out is how to arrange my attributes or styles such that it doesn't affect other text. Notice in my screenshots below that the button text is also getting larger when I use this theme.
Ideally, I think I want a theme to be able to specify attributes that will only apply to the main view with something like:
<item name="mainViewTextSize">18sp</item>
And then I would somehow reference mainViewTextSize from my TextView. Or I'd like to use:
<item name="textSizeTertiary">18sp</item>
because textColorTertiary seems to affect the text in the main view, but not the buttons. But no such attribute exists.
I'm not sure if this is possible, or if I'm approaching this from the wrong direction.
Upvotes: 0
Views: 586
Reputation: 25601
A file attrs.xml
can be added to the Resources\values\
directory with content like this:
<?xml version="1.0" encoding="utf-8" ?>
<resources>
<attr name="mainViewTextSize" format="dimension"/>
</resources>
to define a custom attribute name.
This attribute can be referenced in the themes.xml file like this:
<style name="Theme.StoryvoqueFancy" parent="@style/Theme.StoryvoqueLight">
<item name="mainViewTextSize">18sp</item>
<item name="android:textColorTertiary">#000000</item>
</style>
Then the axml layout file can reference it like this:
<TextView
android:id="@+id/descriptionText"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:textSize="?mainViewTextSize" />
However, it appears necessary, then to define mainViewTextSize in every theme, otherwise an error will be encountered:
Unhandled Exception:
Android.Views.InflateException: Binary XML file line #1: Binary XML file line #1: Error inflating class occurred
It also appears important to avoid recursion (don't default the value of mainViewTextSize
to android:textSize
) otherwise the same error will be encountered.
After taking the other answer into account, I have arrived at the following themes.xml file:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="TextAppearance.Storyvoque.MainView" parent="@android:style/TextAppearance.DeviceDefault" />
<style name="Theme.StoryvoqueLight" parent="@android:style/Theme.DeviceDefault.Light.DarkActionBar">
<item name="android:actionBarSize">32dip</item>
<item name="android:actionBarStyle">@style/Theme.StoryvoqueLight.ActionBar</item>
<item name="mainViewStyle">@style/TextAppearance.Storyvoque.MainView</item>
</style>
<style name="Theme.StoryvoqueLight.ActionBar" parent="@android:style/Widget.DeviceDefault.Light.ActionBar.Solid">
<item name="android:titleTextStyle">@style/Theme.StoryvoqueLight.ActionBar.TitleTextStyle</item>
</style>
<style name="Theme.StoryvoqueLight.ActionBar.TitleTextStyle" parent="@android:style/Widget.Material.ActionBar.Solid">
<item name="android:textSize">18sp</item>
</style>
<style name="Theme.StoryvoqueRetro" parent="@android:style/Theme.DeviceDefault">
<item name="android:actionBarSize">32dip</item>
<item name="android:actionBarStyle">@style/Theme.StoryvoqueLight.ActionBar</item>
<item name="android:windowBackground">@android:color/background_dark</item>
<item name="mainViewStyle">@style/TextAppearance.Storyvoque.Retro</item>
</style>
<style name="TextAppearance.Storyvoque.Retro" parent="@android:style/TextAppearance.DeviceDefault">
<item name="android:textColor">#00FF00</item>
</style>
<style name="Theme.StoryvoqueFancy" parent="@style/Theme.StoryvoqueLight">
<item name="android:windowBackground">@color/papyrus</item>
<item name="mainViewStyle">@style/Theme.StoryvoqueFancy.Text</item>
<item name="android:lineSpacingExtra">8dp</item>
</style>
<style name="Theme.StoryvoqueFancy.Text" parent="@style/TextAppearance.Storyvoque.MainView">
<item name="android:textSize">18sp</item>
<item name="android:textColor">#000000</item>
</style>
</resources>
My axml file contains this:
<TextView
android:id="@+id/descriptionText"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:textAppearance="?mainViewStyle"
My attrs.xml file contains this:
<?xml version="1.0" encoding="utf-8" ?>
<resources>
<attr name="mainViewStyle" format="reference"/>
</resources>
I'm still not sure if this is ideal, but it seems slightly better-designed that my earlier solution, and seems good enough to me in the absence of any further suggestions.
Upvotes: 1
Reputation: 13176
Given that themes are global and styles are local, you would want to be creating a specific style that is applied to the View
level instead of globally.
With that said you should define a TextAppearance
that your style will inherit and ultimately be applied to your View
. If you need any customization on the style, you can create custom style attributes.
Upvotes: 1