I was trying to apply a style to an EditText to change it's colorAccent, I tried to set its style and android:textAppearance, but it completely ignored my new settings. The only way I got it to work was by setting its android:theme.
Am I doing something wrong or is this expected behavior? Why?
My style:
<style name="bright_color_cursor" parent="AppTheme">
<item name="colorAccent">#color/primaryBrightColor</item>
<item name="android:textColorHighlight">#color/primaryBrightColor</item>
</style>
My EditText:
<EditText
android:id="#+id/edit_text"
android:theme="#style/bright_color_cursor"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:background="#android:color/transparent"
android:ems="10"
android:hint="#string/hello"
android:inputType="textCapWords"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="#+id/name_edit_text"
app:layout_constraintTop_toBottomOf="#+id/divider" />
Changing android:theme to any of this settings won't work:
style="#style/bright_color_cursor"
or
android:textAppearance="#style/bright_color_cursor"
Yep, this behavior is to be expected with an EditText. We need to style it by using the android:theme property.
When using #style, the EditText doesn't use the values that we set (and thus the style seems to be ignored). This is, because the EditText creates some children views that are not being styled. See my detailed explanation below.
Detailed explanation and the cause
1) First, the meanings of the options tried and what these do:
style: (Note: not prefixed with android:): This sets the styles only for the component itself and does not change the styles of it's underlying children views/layouts.
android:theme: This basically applies to style to itself and applies the style to it's children views/layouts.
android:textAppearance: This one behaves just like #style for styling.
2) The EditText functionality
As we can imagine: an EditText is not just a simple view. It has a background drawable and handles interaction and such. It simply needs some additional views (and logic) for this functionality to work.
For the functionality of the EditText, it adds some subviews as children to be able to do what we expect from it.
3) Back to theming
The subviews that the EditText adds to do it's functionality, are styled just like the other views are being styled. Which means that the child views only inherit the style when we use the android:theme property. Because this property causes it to style the children views too.
And, if we use #style on the edittext, the children will not get this style.
4) Why this happens (only) for EditText?
Well, not really only... The base view of an EditText is a TextView, but a TextView doesn't provide the functionality that an EditText needs. So the EditText adds additional functionality itself.
A Button for example has the TextView as base too. But this class has enough views with the text and background it gets from the base class, and thus a Button doesn't need to add additional views for it's functionality. So for this, using #style works as it creates no children views to style.
Having said this, a small remark:
In fact, in the source the TextView actually contains the editting logic, but in case of a Button it simply doesn't execute that part of code. (A button doesn't need the Editting functionality, thus it's not being executed)
Related
I read about Android styles and themes today and tried to apply it to a list in my app as a test. The app has a list element which have TextViews added to it programmatically.
According to the docs applying a style as a theme affects child views too.
So I tried this:
<ListView
android:id="#+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/TextAppearance.AppCompat.Small"/>
I expected that the TextView texts in the list became small, but nothing happened.
I also tried #style/TextAppearance.MaterialComponents.Headline1, but it had no effect either.
Why is that?
I didn't change any of the style or theme settings myself. I use the default settings which Android Studio generated for the project.
Shouldn't applying a style as a theme to a view like above change something?
You are using the style "TextAppearance.AppCompat.Small" which is applicable to a TextView and not a generic one like ListView.
You need to apply the style to the list item which is the TextView. You can create a custom style for text appearance, font, sizing, etc and reuse it in your entire app.
If you are creating your views programmatically, you can use a custom adapter (which extends your default adapter), override getView method to apply your style. Refer this
Refer to this awesome article by #Nick Butcher
As my title, when I'm using a theme, style or text appearance, which one takes precedent?
Is there any way I can use all three of them? Thanks!
According to the docs, the priorities are as follows:
Applying character- or paragraph-level styling via text spans to
TextView-derived classes
Applying attributes programmatically
Applying individual attributes directly to a View
Applying a style to a View
Default styling
Applying a theme to a collection of Views, an activity, or your
entire app
Applying certain View-specific styling, such as setting a
TextAppearance on a TextView
I have a basic question about styles/theme application to actual objects.
Firstly from android documentation Link here
A theme is a style applied to an entire Activity or application,
rather than an individual View (as in the example above). When a style
is applied as a theme, every View in the Activity or application will
apply each style property that it supports.
and from the same article
However, if you apply a style to a View that does not support all of
the style properties, the View will apply only those properties that
are supported and simply ignore the others.
So say I use a native theme of a platform in the android manifest file in the application element.
android:Theme.Holo.Light
So per documents each and every view in all activities/application will be applied style properties from the theme above.
Say I have only one custom style in the entire application and I used it on a button.
<style name="RedColor">
<item name="android:textColor">#FF0000</item>
</style>
<Button
style="#style/RedColor"
android:text="#string/hello" />
So all views in the application will be applied main style/theme android:Theme.Holo.Light
But one view (Button) gets applied my custom style called RedColor.
In RedColor style I did not specify any other properties for button and I also did not intentionally inherit the style from any other.
The document says the View will apply only those properties that
are supported and simply ignore the others.
The Question is when this particular view (Button) becomes an actual object and ofcourse the Button has more than textColor as its members how does android populate the remaining properties of this Button or View ?
Basically if I am not wrong,
As per your question at first the Button will be applied the default theme of the activity. After that when the Button is inflated to display inside the Activity, it will see for the button properties and apply to that button which are applicable to Button.
I am trying To show a dialog from a PreferenceActivity, which is set to Theme.Light. The dialog shows with dark text on a dark background:
I assume it uses dark text because it is inheriting the text color from the parent activity, or something similar. I would like the dialog to either use white text on the dark background, or use a white background with dark text, as the PreferenceActivity does when set to Theme.Light.
This seems to be a known problem, the workarounds I have found involve creating and using a custom style that extends Theme.Dialog and using it to instantiate the dialog. Something like:
<style name="CustomDialog" parent="#android:style/Theme.Dialog">
<item name="android:textColor">?android:attr/textColorPrimaryInverseDisableOnly</item>
</style>
Dialog dialog = new Dialog(context, R.style.CustomDialog);
I tried this, but it made no difference. I also tried a number of different values for textColor, none of which modified the Dialog's text color. As a sanity check, I added:
<item name="android:background">#FFFF0000</item>
to the style, which resulted in a dialog with a red background (so I am sure that I am instantiating the dialog properly).
The closest I have come to a solution is just setting the dialog's background color to white, which gives the below dialog. But this is not a good solution, because some version or some device might not use the same behavior I am seeing when inverting text color:
So, is there a good way to set text color on a dialog displayed from a Theme.Light activity?
I assume that you use AlertDialog.Builder and set the list using one of the setSingleChoiceItems methods which doesn't use your own ListAdapter. Instead it creates its own instead with the wrong style. To fix this, you should call setSingleChoiceItems(ListAdapter adapter, int checkedItem, DialogInterface.OnClickListener listener) and provide such an adapter which would use a layout with the needed style.
Now, why this happens. The actual adapter creation happens in the file com.android.internal.app.AlertController, where the following line selects the layout for single choice lists:
int layout = mIsSingleChoice
? R.layout.select_dialog_singlechoice : R.layout.select_dialog_item;
Here is the aforementioned layout:
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="#android:color/primary_text_light_disable_only"
android:gravity="center_vertical"
android:paddingLeft="12dip"
android:paddingRight="7dip"
android:checkMark="#android:drawable/btn_radio"
android:ellipsize="marquee"
/>
As you can see, the line which sets the text color contains not a reference to a theme, but a hardwired color. That's why when this thing gets inflated during the list creation, it will always use the same color, regardless of what style you want it to use. So the right action to overcome this problem is to use your own layout and your own ListAdapter.
I have an android application that I'm working on with a custom theme applied to it in the android manifest on the main activity itself. This activity creates a listview, which has the style applied to it.
If I create a custom layout for that listview, including a separate xml file for the rows themselves, and I apply styling directly to those layouts, does this style overwrite the overall style for the application? I'm trying to get a grasp on the hierarchy of events as far as how styling and themeing works.
The way I'm GUESSING it works in my example is: apply style for row, referenced by row layout xml > apply style for overall listview, referenced by listview layout xml > apply style from custom theme, referenced by style xml referenced by android manifest
Am I right? Or am I approaching this incorrectly. (just for confusions sake, by ">" I mean has a greater importance than)
If you've specified the same attributes in multiple places, the list below determines which attributes are ultimately applied. The list is ordered from highest precedence to lowest:
Applying character- or paragraph-level styling via text spans to TextView-derived classes
Applying attributes programmatically
Applying individual attributes directly to a View
Applying a style to a View
Default styling
Applying a theme to a collection of Views, an activity, or your entire app
Applying certain View-specific styling, such as setting a TextAppearance on a TextView
Hope I am understand your question right here...
The styles you define in styles.xml will always overwrite the styles coming from the theme currently used by android.
But this only works for the attributes you overwrite.
If you leave an attribute untouched, android will provide the style for it, and sometimes this comes bite you in the butt :)
This system is best described like this:
A textview requires an attribute example
<item name="android:textColor">#00FF00</item>
Android will first look in the original layout.
If not found, it will look into your custom styles.
If not found, it will look into android styles.
Hope this helps.
The standard themes have lines like which define the ListView style:
<item name="listViewStyle">#android:style/Widget.ListView</item>
In your own theme you can do a
<item name="listViewStyle">#style/MyOwnListView</item>
Something that is not defined in the ListView style (own or default) will be what is defined in the theme if you have defined it there.