fonix232
fonix232

Reputation: 2195

Overriding editTextStyle doesn't work with latest Material Components base style

In an app of mine, I'm using the Theme.MaterialComponents.Light.NoActionBar as a base style. In this style, which I call AppTheme, I'm trying to override editTextStyle to provide a custom style for com.google.android.material.textfield.TextInputEditText (according to the source code, it uses R.attr.editTextStyle as a default style).

This is my current theme, related to the TIEditText and TILayout:

<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
    [ primary and secondary colors, OnColors, etc.]
    <item name="editTextStyle">@style/AppTheme.TextInputEditText</item>
    <item name="textInputStyle">@style/AppTheme.TextInputLayout</item>

    [ Custom attribute for testing, defined in attrs.xml ]
    <item name="textInputEditTextStyle">@style/AppTheme.TextInputEditText</item>
</style>

For some reason, even though I set editTextStyle, if I use it in code, it does not get applied:

<com.google.android.material.textfield.TextInputLayout
    android:id="@+id/tilFirstName"
    style="?attr/textInputStyle"
    android:hint="@string/label_firstname"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent">

    <com.google.android.material.textfield.TextInputEditText
        android:id="@+id/firstName"
        style="?attr/editTextStyle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="textPersonName"
        android:text="@={viewModel.firstName}" />
</com.google.android.material.textfield.TextInputLayout>

However if I replace the style of firstName with ?attr/textInputEditTextStyle, it works.

Why can't I override editTextStyle in the default theme? What the hell is going on?

Target SDK is 28, minSDK is 21, Material library version is 1.1.0-alpha06

Upvotes: 13

Views: 3710

Answers (2)

rmirabelle
rmirabelle

Reputation: 6446

Let's just move past the part where we all recognize that Android themes and styles are singularly the most absurd wasteland of hackery and guesswork ever devised by human beings.

This is an expansion on the previous answer. Same silly 'hack'. I was able to style the TextInputEditText by setting editTextStyle, but not where it intuitively belongs, but rather inside a custom materialThemeOverlay nested within the style defined for textInputStyle. Witness:

<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
    <!-- works fine -->
    <item name="textInputStyle">@style/AppTheme.TextInputLayoutStyle</item>
    <!-- should work fine, doesn't work, happily ignored -->
    <!-- <item name="editTextStyle">@style/AppTheme.TextInputEditTextStyle</item> -->
</style>

<style name="AppTheme.TextInputLayoutStyle" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox">
    <!-- other props (boxBackgroundMode, boxBackgroundColor, boxStrokeColor, etc) -->
    <!-- can we set editTextStyle from here? Of course not! We should magically know we need a material theme overlay-->
    <item name="materialThemeOverlay">@style/AppTheme.MaterialThemeOverlay</item>
</style>

<!-- style inception! a style, child of another style, whose only purpose is to refer to yet another style -->
<style name="AppTheme.MaterialThemeOverlay">
    <item name="editTextStyle">@style/AppTheme.TextInputEditTextStyle</item>
</style>

<!-- finally, the style we SHOULD have been able to set from the theme -->
<style name="AppTheme.TextInputEditTextStyle" parent="@style/Widget.MaterialComponents.TextInputEditText.OutlinedBox">
    <item name="android:textColor">@color/white</item>
</style>

All of the above ridiculousness and ANOTHER day of my life thrown in the trash, just to change the color of text. Thaaaaanks Aaaaaandroid.

Upvotes: 37

Gabriele Mariotti
Gabriele Mariotti

Reputation: 363677

For some reason, even though I set editTextStyle, if I use it in code, it does not get applied

It happens because the default styles of the TextInputLayout override the editTextStyle using the materialThemeOverlay attribute.

For example the Widget.MaterialComponents.TextInputLayout.FilledBox has this default style:

<style name="Widget.MaterialComponents.TextInputLayout.FilledBox" parent="Base.Widget.MaterialComponents.TextInputLayout">
    <item name="materialThemeOverlay">
       @style/ThemeOverlay.MaterialComponents.TextInputEditText.FilledBox
    </item>
    ....
</style>
<style name="ThemeOverlay.MaterialComponents.TextInputEditText.FilledBox">
    <item name="editTextStyle">@style/Widget.MaterialComponents.TextInputEditText.FilledBox</item>
</style>

Upvotes: 9

Related Questions