Найти тему
sashatinkoff

TextInputLayout и темная тема

В Material2 завезли новые стили для старых добрых EditText’ов. Теперь это уже не страшная мешанина цветов и градиентов, как было раньше. Мы (разработчики) теперь можем не только в полоски снизу делать, но и нам из коробки добавили немного побольше кастомизации. К примеру, в последних проектах я использую вот такой стиль в формочках

Стильно, модно, молодежно, словом, материально-два-нольно. К сожалению, в этой бочке не без ложки дегтя — кастомизация вдруг ограничена не вашим воображением (или, скажем, опытом, знаниями, умениями короче — желанием), а увы — сверху. Например, цвет бордера (как это по русски-то сказать? Бордюр — не звучно, поребрик — тоже не то…). Стилями его не поменять, не завезли… в отличие кстати от слухов про темные темы в грядущей десятке Android Q. Как быть?

Читать сурсы — мне помогло. Можно конечно и свои блекджеки писать — велосипеды никто и в 2019 не отменял — кастомные вьюшки писались, пишутся и будут писаться. Но я покажу вам как с помощью небольших исследований получить следующую картинку

-2

Цвет текста инпута — это самое простое. Решение в “лоб” — это написать в нашем layout следующее

android:textColor="#6CA4C5"

Более правильным решением будет создание стиля для AppCompatEditText, которое мы будем потом присваивать нужным контролам. Это настолько тривиально, что даже примеров приводить не буду.

А вот что касается подсказок и активных границ — без примеров в styles.xml не обойтись. Сначала давайте посмотрим, как выглядит наш контрол в лейауте

<com.google.android.material.textfield.TextInputLayout
style="@style/YTextInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Please enter your name"
app:hintTextAppearance="@style/TextInputHintTextAppearance">

<androidx.appcompat.widget.AppCompatEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#6CA4C5" />

</com.google.android.material.textfield.TextInputLayout>

Сначала разберем стиль YTextInputLayout

<style name="YTextInputLayout" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox">
<item name="boxStrokeColor">@color/colorAccent</item>
<item name="boxStrokeWidth">1dp</item>
<item name="android:textColorHint">#FF00</item>
</style>

Первые две строчки управляют стилем границ:

  • boxStrokeColor — какого цвета будут границы нашего контрола в активном состоянии
  • boxStrokeWidth — размер границ
  • android:textColorHint — цвет подсказки в нективном состоянии

Выглядит все немного запутанно (на самом деле так и есть!). Давайте рассмотрим следующий стиль TextInputHintTextAppearance

<style name="TextInputHintTextAppearance" parent="TextAppearance.AppCompat">
<item name="android:textSize">12sp</item>
<item name="android:textColor">#FF0</item>
</style>

Эта пара строк — все про активное состояние нашей подсказки

  • android:textSize — размер подсказки, в скриншоте желтого цвета.
  • android:textColor — цвет этой подсказки

На самом деле найти все это довольно просто, а вот что касается цвета границ в неактивном состоянии (не в фокусе) — вот где самая интрига.

Рассматривая исходники класса TextInputLayout я выделил для себя свойства, для которых есть данные в стилях, а вот что касается defaultStrokeColor — тишина, только получение цвета и ресурса colors

this.boxCollapsedPaddingTopPx = a.getDimensionPixelOffset(styleable.TextInputLayout_boxCollapsedPaddingTop, 0);
this.boxCornerRadiusTopStart = a.getDimension(styleable.TextInputLayout_boxCornerRadiusTopStart, 0.0F);
this.boxCornerRadiusTopEnd = a.getDimension(styleable.TextInputLayout_boxCornerRadiusTopEnd, 0.0F);
this.boxCornerRadiusBottomEnd = a.getDimension(styleable.TextInputLayout_boxCornerRadiusBottomEnd, 0.0F);
this.boxCornerRadiusBottomStart = a.getDimension(styleable.TextInputLayout_boxCornerRadiusBottomStart, 0.0F);
this.boxBackgroundColor = a.getColor(styleable.TextInputLayout_boxBackgroundColor, 0);
this.focusedStrokeColor = a.getColor(styleable.TextInputLayout_boxStrokeColor, 0);
this.boxStrokeWidthDefaultPx = context.getResources().getDimensionPixelSize(dimen.mtrl_textinput_box_stroke_width_default);
this.boxStrokeWidthFocusedPx = context.getResources().getDimensionPixelSize(dimen.mtrl_textinput_box_stroke_width_focused);
this.boxStrokeWidthPx = this.boxStrokeWidthDefaultPx;
int boxBackgroundMode = a.getInt(styleable.TextInputLayout_boxBackgroundMode, 0);
this.setBoxBackgroundMode(boxBackgroundMode);
if (a.hasValue(styleable.TextInputLayout_android_textColorHint)) {
this.defaultHintTextColor = this.focusedTextColor = a.getColorStateList(styleable.TextInputLayout_android_textColorHint);
}

this.defaultStrokeColor = ContextCompat.getColor(context, color.mtrl_textinput_default_box_stroke_color);
this.disabledColor = ContextCompat.getColor(context, color.mtrl_textinput_disabled_color);

Получается, вся хитрость — это переназначить цвет mtrl_textinput_default_box_stroke_color в своих ресурсах? Я так и сделал, собственно, чтобы получить нужный результат:

<color name="mtrl_textinput_default_box_stroke_color" tools:override="true">#FFF</color>

Вот и все расследование!

Ссылка на пример с готовыми файлами https://github.com/sashatinkoff/TextInputLayout-Outline-Style/