TextAppearance not being applied on some API versions - android

I have a view I have created in XML. The view is then shown on one of two fragments. Either as the pause menu, replacing the board in my game activity, or a score summary at the end of a round on a DialogFragment.
Each TextView on my summary sets its textAppearance using an attribute declared in the theme for the view. This works without problem on my Sony Xperia Z3 Compact, running API 22. However, the text appearance doesn't seem to be applied at all on my wifes phone. Her's is a Z3 Compact running API 19. I also have a tablet running API 17 with the same problem.
On each of the devices with the problem, all the text is displayed with a very small text size. It also ignores the textColor set by the style.
The XML for each component looks like a variation on this:
<TableRow android:id="#+id/view_score_summary_group_overall_time">
<TextView
android:text="#string/time"
android:textAppearance="?scoreSummaryTextAppearanceHeading"
/>
<TextView android:id="#+id/view_score_summary_game_time"
android:layout_column="2"
android:textAppearance="?scoreSummaryTextAppearanceData"
/>
</TableRow>
The attribute is then defined in my theme like this:
<style name="ScoreSummary.Light">
<item name="scoreSummaryTextAppearanceHeading">#style/ScoreSummary.Light.TextAppearance.Heading</item>
<item name="scoreSummaryTextAppearanceTitle">#style/ScoreSummary.Light.TextAppearance.Title</item>
<item name="scoreSummaryTextAppearanceData">#style/ScoreSummary.Light.TextAppearance.Data</item>
</style>
The styles are then defined like this:
<style name="ScoreSummary">
</style>
<style name="ScoreSummary.Light">
</style>
<style name="ScoreSummary.Light.TextAppearance">
<item name="android:textColor">#color/text_score_summary_light</item>
</style>
<style name="ScoreSummary.Light.TextAppearance.Title">
<item name="android:textSize">24sp</item>
</style>
<style name="ScoreSummary.Light.TextAppearance.Heading">
<item name="android:textSize">16sp</item>
<item name="android:gravity">start</item>
</style>
<style name="ScoreSummary.Light.TextAppearance.Data">
<item name="android:textSize">16sp</item>
<item name="android:gravity">end</item>
</style>
I then set the theme on the view (on my game activity) like this:
<com.abc.def.ScoreSummaryView android:id="#+id/fragment_game_score_summary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:layout_gravity="center"
android:theme="#style/ScoreSummary.Light"
/>
So far I have tried a number of things:
Setting the attributes individually on the TextView.
android:textSize="150sp"
This worked. But if you have to set that on every component, why bother with styles at all.
Setting textAppearanceSmall instead of textAppearance. Based on this. This just made all the text slightly larger, but still didn't apply my style.
Setting style instead of textAppearance. This had the same result as setting textAppearanceSmall.
Making my style declarations extend "android:attr/textAppearance". Didn't change anything, and I'm not sure why it would but I was desperate.
I've been looking at this for ages now, and I've tried googling a whole load of things but just can't get anywhere.
This is it looking wrong. On my tablet - though it looks similar on my wifes phone.
This is how it's supposed to look. On my phone.

Related

How to define textAppearence value in android layout

In my layout, I am using falling for predefined values for android:textAppearence. But, there are, as I found, at least 2 ways to define them, which yields a very different result (like, different font size and alpha and weight value):
android:textAppearance:="#style/TextAppearance.MaterialComponents.Caption". This #style/... values are defined in (in my case) in a file
~/.gradle/caches/transforms-2/files-2.1/11ab83d2971a1126be493aa33fdd0f6e/material-1.1.0/res/values. This, for example, is defined as:
<style name="TextAppearance.MaterialComponents.Caption" parent="TextAppearance.AppCompat.Caption">
<item name="fontFamily">sans-serif</item>
<item name="android:fontFamily">sans-serif</item>
<item name="android:textStyle">normal</item>
<item name="android:textAllCaps">false</item>
<item name="android:textSize">12sp</item>
<item name="android:letterSpacing">0.0333333333</item>
</style>
android:textAppearance="#android:style/TextAppearance.Material.Menu". This is defined in
/home/rudra/.Android/Sdk/platforms/android-29/data/res/values/styles_material.xml. This is defined as:
<style name="TextAppearance.Material.Menu">
<item name="textSize">#dimen/text_size_menu_material</item>
<item name="fontFamily">#string/font_family_menu_material</item>
</style>
The main problem to me is, I am not sure which one to use for more consistent user experience. I am sure, the file for case 2 will not be shipped with my app, but maybe the user will have styles_material for his android-xx. But by realizing how values have changed with material-1.0.0 and 1.1.0, I am a bit sKeptic to depend on these values, but I am not sure.
On the other hand, this is a considerable work to redefine textAppearance for all possible scenarios.
So, I am looking for suggestions on how to define the textAppearence, and among case 1 and case 2, which should I use for more consistent result across devices
If you want to define a custom textAppearance, you can define as follow. I use material-components-android.
In style.xml
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.MaterialComponents.Light">
<!-- Customize your theme here. -->
<item name="colorPrimary">#color/primaryColor</item>
<item name="colorPrimaryDark">#color/primaryDarkColor</item>
<item name="colorPrimaryVariant">#color/primaryLightColor</item>
<item name="colorOnPrimary">#color/primaryTextColor</item>
<item name="colorSecondary">#color/secondaryColor</item>
<item name="colorSecondaryVariant">#color/secondaryDarkColor</item>
<item name="colorOnSecondary">#color/secondaryTextColor</item>
<!-- This line is important -->
<item name="textAppearanceHeadline3">#style/TextAppearance.Headline3</item>
</style>
<style name="TextAppearance.Headline3" parent="TextAppearance.MaterialComponents.Headline3">
<!-- Define your custom appearance here. -->
<item name="fontFamily">#font/work_sans_black</item>
<item name="android:textAllCaps">false</item>
<item name="android:textSize">#dimen/text_size</item>
<item name="android:textStyle">bold</item>
<item name="android:textColor">#color/primaryTextColor</item>
</style>
You can use this-TextAppearance.Headline3 in layout as follow.
<TextView
android:id="#+id/tvAppName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/app_name"
android:textAppearance="?attr/textAppearanceHeadline3"
/>
This is my usage for custom text appearance. You can define as you like.
If you want to customize theme or style, you have to know common attributes. You can see it at this article.
I hope this will be helpful for you.
Looking at TextView.java, there don't appear to be any attributes that are defined by android:textAppearance that are not able to be set on a TextView directly. So there doesn't appear to be any technical reason that one needs to use them over defining attributes in styles directly, at least in one's ability to configure how a TextView looks.
This means that you can avoid using it in your layouts as well as your styles without any adverse effects, provided that you override all the associated attributes. The base theme defines many different standard android:textAppearances for the various widgets, so you should check that all the widgets are properly overridden.
Based on my experience, android:textAppearance is most useful if you wish your app to appear to integrate into the rest of the device. So if you need big text, you can use android:textAppearance="?android:attr/textAppearanceLarge" and now your text is large! No need to know how many sp that means for the given device/screen size/etc..
However if your app is highly styled and you'd otherwise be overriding all the text sizes anyhow, the value-add of android:textAppearance diminishes. You can certainly use it as referenced in the posts above, but if that doesn't fit into your styling system, then feel free to omit it. It's just another tool to help you get a good-looking app across all devices.
I would also recommend making extra-sure that you try your app across a variety of devices if you choose not to use it, just to make sure that you didn't neglect to override a default android:textAppearance.

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.

Missing TextAppearances.Micro style

According to Android Developer Design Style for Typography, there are 4 TextAppearances (Micro, Small, Medium, Large).
But there is no predefined style for Micro:
?android:attr/textAppearanceMicro
android:style/TextAppearance.Micro
None of them can be found in sources of Android. What am I missing?
Good question! After researching a little bit, I didn't find any results for "TextAppearance.Micro".
On the other hand, I found the official Android source for style resource related to TextAppearances.
<style name="TextAppearance.Small">
<item name="android:textSize">14sp</item>
<item name="android:textColor">?textColorSecondary</item>
</style>
<style name="TextAppearance.Medium">
<item name="android:textSize">18sp</item>
</style>
<style name="TextAppearance.Large">
<item name="android:textSize">22sp</item>
</style>
As you can see, all of them only affect the text size (except TextAppearance.Small, which also affect the text color). So, I can safely say that the site displays the text sizes as a guideline only. On the other hand, you can always add a custom style to support TextAppearance.Micro! Just insert this inside styles.xml.
<style name="TextAppearance.Micro" parent="#android:style/TextAppearance.Small">
<item name="android:textSize">12sp</item>
</style>
and use it like:
<TextView
...
android:textAppearance="#style/TextAppearance.Micro" />
On a bit related note, when I searched "textAppearanceMicro", I found 3 projects on GitHub. All of them adding some custom attributes, which one of them is textAppearanceMicro. Also, all of them are using ActionBarSherlock. I don't know whether there is a connection between textAppearanceMicro and ActionBarSherlock, but I didn't find that attribute was used anywhere in the code.
If you happen to use the Google AppCompat Library, you can use the following:
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="#style/TextAppearance.AppCompat.Caption" />

Change holo spinner text colour

I have a spinner in a Holo theme dialog and am trying to change the text colour because it is very hard to read:
I have looked at android styles.xml, as well as many other answers, and believe that I am setting the custom style correctly; but it's just not getting picked up.
This is an extract from the dialog layout file where the spinner lives:
<Spinner
android:id="#+id/spn_Type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:entries="#array/dose_type_options"
style="#style/DialogSpinner" />
And these are the relevant entries in styles.xml in the values-v14 folder:
<style name="DialogSpinner" parent="#android:style/Widget.Holo.Spinner">
<item name="android:spinnerItemStyle">#style/MySpinnerItem</item>
</style>
<style name="MySpinnerItem" parent="android:Widget.Holo.TextView.SpinnerItem">
<item name="android:textAppearance">#style/MyTextAppearanceSpinnerItem</item>
</style>
<style name="MyTextAppearanceSpinnerItem" parent="android:TextAppearance.Holo.Widget.TextView.SpinnerItem">
<item name="android:textColor">#FFF</item>
</style>
The dialog itself is forced to the Holo dark theme by using:
<style name="FibroDialog" parent="#android:style/Theme.Holo.Dialog">
</style>
Can anyone identify why the spinner text isn't white?
I have looked at other solutions, which suggest changing the colour in code, but this app supports 2.3.* upwards, so for those non-holo versions black text is fine, hence trying to do it by styles.
Thanks
Updated using answer from Woda below
The text colour of the initial value of the spinner is now white, which goes a long way to highlighting that there is a spinner there for the user:
But the text colour of the selectable items is still black. I guess it's not a massive deal, at least the existence of the spinner has been affirmed by getting the initial text changed to white. But I would be interested to know why the items are still black, and how to change them to white.
Have you tried to accept the SpinnerItemStyle to your Theme? So all Spinners in your App would've the same style. I'm using it like this and it works:
theme.xml:
<style name="exampleTheme" parent="android:Theme.Holo.Light">
<item name="android:spinnerItemStyle">#style/SpinnerItem_example</item>
...
</style>
style.xml:
<style name="SpinnerItem_example" parent="android:TextAppearance.Widget.TextView.SpinnerItem">
<item name="android:textColor">#000000</item>
</style>
Update:
Taking a deeper look into the styles.xml brought me this:
<style name="Widget.DropDownItem.Spinner">
<item name="android:checkMark">?android:attr/listChoiceIndicatorSingle</item>
</style>
<style name="Widget.DropDownItem">
<item name="android:textAppearance">#style/TextAppearance.Widget.DropDownItem</item>
<item name="android:paddingStart">#dimen/dropdownitem_text_padding_left</item>
<item name="android:paddingEnd">#dimen/dropdownitem_text_padding_right</item>
<item name="android:gravity">center_vertical</item>
</style>
So you probably need to customize the Widget.DropDownItem and accept it in your theme.
...
<item name="dropDownItemStyle">#android:style/Widget.DropDownItem</item>
...
For customizing my application the following two links helped me a lot to understand the structure of the different views. These two files are part of the android source code. May be it helps you too.
themes.xml
styles.xml
I fixed it by calling
mArrayAdapter.setDropDownViewTheme(mActivity.getTheme());
Hope this helps someone ;)
You can access the internal TextView in code without changing any styles. This is how I handled enabling and disabling Spinners
The .getSelectedView() did not work for me. So I tricked the Spinner to "show" being disabled.
You will need to define your own colors for the "disabled" look.
For Example:
R.color.blue_text //means enabled
R.color.gray_text //means disabled
So to disable my spinner:
((TextView)mySpinner.getChildAt(0)).setTextColor(getResources().getColor(R.color.gray_text));
mySpinner.setEnabled(false);
mySpinner.setFocusable(false);
To enable my spinner:
((TextView)mySpinner.getChildAt(0)).setTextColor(getResources().getColor(R.color.blue_text));
mySpinner.setEnabled(true);
mySpinner.setFocusable(true);
The getChildAt(0) function allows you to access the first item in the spinner, which is what you show on the screen as a TextView.
You don't need to change styles or modify any XML. Just do this in your code, even within event methods, you should be fine.

EditText Styling

Is it possible to manipulate the style of a text field found in API 17 of android in API 8 ??
The text field in lower API's are very different in comparison with the higher API's. Is there any way to give a uniform look and feel for these components?
To use Android v8 EditText style, change the background of the editText:
android:background="#android:drawable/edit_text"
or use the whole style used in v8:
<style name="Widget.EditText">
<item name="android:focusable">true</item>
<item name="android:focusableInTouchMode">true</item>
<item name="android:clickable">true</item>
<item name="android:background">#android:drawable/edit_text</item>
<item name="android:textAppearance">?android:attr/textAppearanceMediumInverse</item>
<item name="android:textColor">#android:color/primary_text_light</item>
<item name="android:gravity">center_vertical</item>
</style>
Only the EditText? Or do you want every widget to look like pre holo widgets? If so, then setting this as your theme will help:
<application
[...]
android:theme="#android:style/Theme" >
[...]
</application>
However if you just want to have the EditText to be "un-holofied" you can do this:
<EditText
android:id="#+id/spinnermap"
style="#style/MyEditText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true" />
values/styles.xml:
<style name="MyEditText" parent="android:Widget.Spinner"></style>
and set your Theme to Holo(.Light) and Theme(.Light) for pre HC.
Or if you want to combine everything into one theme with everything except the EditText widget being holo, then you can do this:
values-v11/styles.xml: // v11 because pre HC themes already have the EditText style, you want.
<style name="MyTheme" parent="#android:style/Theme.Holo"
<item name="android:editTextStyle">#style/MyEditText></item>
</style>
Or you can use this:
https://github.com/Prototik/HoloEverywhere
if you want to have Holo on older devices (I mean that you can do it in the opposite way - change old controls to look line new ones). This library also works with ActionBar Sherlock.

Categories

Resources