Переопределение editTextStyle не работает с последним базовым стилем компонентов материала.

В моем приложении я использую Theme.MaterialComponents.Light.NoActionBar в качестве базового стиля. В этом стиле, который я называю AppTheme, я пытаюсь переопределить editTextStyle, чтобы предоставить пользовательский стиль для com.google.android.material.textfield.TextInputEditText (согласно исходному коду, он использует R.attr.editTextStyle как стиль по умолчанию).

Это моя текущая тема, связанная с TIEditText и 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>

По какой-то причине, хотя я установил editTextStyle, если я использую его в коде, он не применяется:

<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>

Однако, если я заменю стиль firstName на ?attr/textInputEditTextStyle, это сработает.

Почему я не могу переопределить editTextStyle в теме по умолчанию? Что, черт возьми, происходит?

Целевой SDK — 28, minSDK — 21, версия библиотеки материалов — 1.1.0-alpha06.


comment
Та же проблема для меня. Потерял много времени и до сих пор не понимаю, почему этот атрибут не применяется.   -  person Alexei Artsimovich    schedule 24.05.2019


Ответы (2)


По какой-то причине, хотя я установил editTextStyle, если я использую его в коде, он не применяется

Это происходит потому, что стили по умолчанию TextInputLayout переопределяют стили editTextStyle с использованием атрибута materialThemeOverlay.

Например, Widget.MaterialComponents.TextInputLayout.FilledBox имеет такой стиль по умолчанию:

<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>
person Gabriele Mariotti    schedule 25.09.2019
comment
Не могли бы вы объяснить, почему вы выбрали переопределение стиля MaterialComponents вместо добавления пользовательского определения по умолчанию? :) Пытаюсь применить, но не понимаю, почему это работает. Спасибо :) - person Josseline Perdomo; 02.10.2019
comment
@JosselinePerdomo Это стиль по умолчанию, предоставляемый компонентами материалов для TextInputLayout.FilledBox. Я объяснил, почему style="?attr/editTextStyle" не работает. Это атрибут по умолчанию, определенный на уровне темы приложения. Он переопределяется самими компонентами (он использует тот же attr, что и materialThemeOverlay). Вместо этого работает textInputEditTextStyle, потому что это настраиваемый атрибут, который не переопределяется. - person Gabriele Mariotti; 02.10.2019

Давайте просто пройдем мимо той части, где мы все признаем, что темы и стили Android — это исключительно самая абсурдная пустошь хакерства и догадок, когда-либо придуманных людьми.

Это расширение предыдущего ответа. Тот же глупый «хак». Я смог стилизовать TextInputEditText, установив editTextStyle, но не там, где это интуитивно понятно, а внутри пользовательского materialThemeOverlay, вложенного в стиль, определенный для textInputStyle. Свидетель:

<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>

Всю вышеперечисленную нелепость и ЕЩЕ ОДИН день моей жизни выкинули на помойку, лишь бы изменить цвет текста. Тааааааааааааааааандроид.

person rmirabelle    schedule 11.02.2020
comment
Большое спасибо) Это было НАСТОЛЬКО запутанно, прежде чем я использовал ваше решение. Для меня это просто ниже понимания того, что все стили - это просто стили, и этот конкретный стиль - это стиль themeOverlayed. - person StayCool; 21.05.2020
comment
Это просто смешно, Гугл. Им действительно нужно переделать всю свою систему тем. Спасибо, что сэкономили мне еще больше бесчисленных часов, пытаясь понять это. - person Stephen; 05.11.2020
comment
В настоящее время мы занимаемся ребрендингом нашего приложения, и я не могу не согласиться с первым предложением. Примите мой голос! - person eHero; 29.07.2021