Как я могу сделать цвет EditText стилизованным с помощью пользовательского атрибута (например, ошибка)?

Я хотел бы сделать EditText, текст которого становится красным, когда выполняется условие "ошибка". Я знаю, что TextInputLayout имеет встроенное состояние ошибки, но я не хочу, чтобы текст находился ниже области ввода, и я не хочу включать библиотеки поддержки дизайна в мой проект (который является SDK - так другие будут включать это). Тем не менее, мой EditText всегда показывает состояние ошибки, и я не знаю, почему.

Мои усилия на данный момент:

Для начала я объявляю стильную вещь. Кажется нормально.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MySpecialEditText">
        <attr name="state_error" format="boolean"/>
    </declare-styleable>
</resources>

Затем я создаю селектор в моем res/colors каталог. Теперь я бы предпочел переопределить цвет, только если мой специальный атрибут установлен. Но если я должен скопировать android:state-pressedи т. д., состояния и все их комбинации, я могу сделать это (и с теми же результатами, см. ниже). Этот файл res/color/red_on_error_dark.xml,

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:custom="http://schemas.android.com/apk/lib/com.mypackage">
    <item
        custom:state_error="true"
        android:color="#f00" />
    <item
        custom:state_error="false"
        android:color="@android:color/primary_text_dark"/>
    <item android:color="@android:color/primary_text_dark"/>
</selector>

И я добавляю свою новую стильную вещь в XML-включение моего пользовательского класса:

<com.mypackage.MySpecialEditText
     android:id="@+id/some_id"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:background="@android:color/transparent"
     android:hint="@string/a_nice_hint"
     android:inputType="number"
     android:textColor="@color/red_on_error_dark"
     />

Все идет нормально. Теперь я создаю свой класс, который расширяет EditText:

public class MySpecialEditText extends EditText {

    private static final int[] STATE_ERROR = {R.attr.state_error};
    private boolean mStateError;
    //... lots of other fun functionality

    // Time to set my custom status
    public void setStateError(boolean stateError) {
        mStateError = stateError;
        invalidate();
        refreshDrawableState();
    }

    // And now, I need to add the custom state drawable.
    @Override
    protected int[] onCreateDrawableState(int extraSpace) {
        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
        if (mStateError) {    
            mergeDrawableStates(drawableState, STATE_ERROR);
        } 
        return drawableState;
    }
}

Все это достаточно легко собрать. Однако когда я запускаю код, он всегда рисует текст красным.

Вещи, которые я проверил:

  1. Что я правильно устанавливаю состояния ошибки / отсутствия ошибок.
  2. Что код проходит через onCreateDrawableState метод во время без ошибок! Это пропускает mergeDrawableStates метод с дополнительным атрибутом. (Я также добавил else предложение и возвращает drawableState без добавления лишних пробелов).
  3. Несмотря на то, что атрибут является логическим, и теоретически должен иметь возможность принимать значение true или false, я добавил отдельный атрибут STATE_VALIDи изменил мой селектор следующим образом.

Я даже зашел так далеко, что сменил селектор на исчерпывающий:

<item custom:state_error="true" android:state_selected="true" android:color="#f00" />
<item custom:state_error="true" android:state_focused="true" android:color="#f00" />
<item custom:state_error="true" android:state_pressed="true" android:color="#f00" />

<item custom:state_error="false" android:state_selected="true" android:color="@android:color/primary_text_dark" />
<item custom:state_error="false" android:state_focused="true" android:color="@android:color/primary_text_dark" />
<item custom:state_error="false" android:state_pressed="true" android:color="@android:color/primary_text_dark" />

И я пошел еще дальше и объединил ненужные дополнительные состояния с кучей android:state_blahТаким образом, у меня есть что-то вроде 20 различных случаев в моем селекторе. (На самом деле, в этом случае он всегда остается белым, что не намного лучше).

Теперь, что я действительно, действительно хотел бы, это объявить настраиваемое значение, которое другие люди (которые используют мой sdk) могут установить значение, если они того пожелают. Но сейчас я буду рад узнать, почему текст всегда красный.

Редактировать: один из вполне законных обходных путей - просто вызвать setTextColor, когда я достигну состояния ошибки в MySpecialEditText, Это мое временное решение, но оно не позволяет кому-либо использовать мой контроль и добавлять custom:state_error=@color/some_custom_colorили аналогичное значение в теме их выбора. Пока я вызываю setTextColor вручную, цвет ошибки всегда является моим конкретным оттенком красного.

Я мог бы пойти дальше и добавить новый конструктор или установщик для цвета ошибки, но это не очень хорошее решение для библиотеки. Если вы используете библиотеку и создаете экземпляр моего контроля, она поднимет все EditText стили у вас уже есть, так что выглядит нативно. И если вы хотите настроить цвет ошибки, я бы хотел, чтобы вы могли сделать это в одном месте для всего вашего приложения с хорошим фрагментом XML, который вы можете запустить дизайнером.

Есть идеи? Упреждающее спасибо всем ответчикам и покушающимся ответчикам.

0 ответов

Другие вопросы по тегам