Проблема с перекрытием подсказки TextInputLayout

Я использую TextInputLayout из библиотеки дизайна Android, чтобы показать ярлык в EditText.

Проблема заключается в том, когда я начинаю работу с того, что текст текста метки (текста) EditText перекрывает фактический текст (на секунду) и только затем возвращается в свое место (вверху EditText).

Чтобы проиллюстрировать эту проблему, я записал короткое видеоролик: https://youtu.be/gy0CzcYggxU

Вот мой activity.xml:

<LinearLayout
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:layout_margin="16dp"
  android:orientation="vertical">

<android.support.design.widget.TextInputLayout
    android:id="@+id/firstNameTextInputLayout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="8dp">

  <EditText
      android:id="@+id/firstNameEditText"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:hint="@string/first_name"
      android:inputType="textCapWords"
      android:textColor="@color/textPrimary"
      android:textColorHint="@color/textSecondary"
      android:textSize="16sp"
      android:theme="@style/CustomEditText"/>
</android.support.design.widget.TextInputLayout>


<android.support.design.widget.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="24dp">

  <EditText
      android:id="@+id/lastNameEditText"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:hint="@string/last_name"
      android:inputType="textCapWords"
      android:textColor="@color/textPrimary"
      android:textColorHint="@color/textSecondary"
      android:textSize="16sp"
      android:theme="@style/CustomEditText"/>
</android.support.design.widget.TextInputLayout>

Ответы

Ответ 1

Наконец, нашли адекватное объяснение проблемы:

Ну, оказывается, что была добавлена ​​оптимизация производительности фреймворк в Android 4.0, который позволил только вашей иерархии представлений один прогон ничьей перед запуском анимации активности. однажды анимация Activity закончилась, ваша иерархия просмотров рисуется каждый ~ 16 мс, как вы ожидаете.

Подробнее: https://medium.com/@chrisbanes

TL;DR: это ограничение платформы, и это поведение будет происходить в более старых версиях (Marshmallow и lower).

В анимации Nougat будет работать как ожидалось без запаздывания.

Ответ 2

Я нашел дешевый обходной путь для этой и другой ошибки.

Подкласс TextInputLayout
Смотрите код для addView()
Если у вас есть текст, установленный в текстовом представлении, когда он надувается, это заставит подсказку свернуться и предотвратит анимацию. Этот код выполняет обходной путь, который будет временно устанавливать текст, пока состояние не будет установлено во время установки. В качестве бонуса есть код, который гарантирует, что подсказка будет нарисована только в случае, если есть только один проход макета.

    public class TextInputLayout extends android.support.design.widget.TextInputLayout {

    public TextInputLayout(Context context) {
        super(context);
    }

    public TextInputLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @SuppressLint("DrawAllocation")
    @Override
    protected void onLayout(final boolean changed, final int left, final int top, final int right, final int bottom) {
        if (ViewCompat.isLaidOut(this)) {
            super.onLayout(changed, left, top, right, bottom);
        } else {
            // Workaround for this terrible logic where onLayout gets called before the view is flagged as laid out.
            // The normal TextInputLayout is depending on isLaidOut when onLayout is called and failing the check which prevents initial drawing
            // If there are multiple layout passes this doesn't get broken
            post(new Runnable() {
                @SuppressLint("WrongCall")
                @Override
                public void run() {
                    TextInputLayout.super.onLayout(changed, left, top, right, bottom);
                }
            });
        }
    }

    @Override
    public void addView(View child, int index, ViewGroup.LayoutParams params) {
        if (child instanceof EditText) {
            EditText editText = (EditText) child;
            if (StringUtils.isEmpty(editText.getText().toString())) {
                editText.setText("  "); // Set filler text so the initial state of the floating title is to be collapsed
                super.addView(child, index, params);
                editText.setText(""); // Set back to blank to cause the hint to animate in just in case the user sets text
                // This prevents the hint from being drawn over text that is set programmatically before the state is determined
                return;
            }
        }
        super.addView(child, index, params);
    }
}

Ответ 3

Вы можете установить подсказки программно с небольшой задержкой. Это не идеальное решение, но, по крайней мере, оно выглядит лучше, чем перекрывающиеся подсказки.

new Handler().postDelayed(
   new Runnable() {
      @Override
      public void run () {
         textInputLayout.setHint("My hint");
      }
   }, 100
);

Ответ 4

Обходной путь, который работал у меня, заключался в обновлении такой активности:

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    textInputLayout.setHintAnimationEnabled(false);
    textInput.setText("sample");
    textInputLayout.setHintAnimationEnabled(true);
    ...
}

Ответ 5

Я думаю, это может быть исправлено для компиляции 'com.android.support:design:23.0.1'

Ответ 6

Daniel Ochoa отметил обходное решение в комментариях, которые работали для меня, - установите начальное состояние для EditText с некоторым текстовым контентом (пустая строка должна это сделать). Это заставит исходное состояние подсказки подняться.

<android.support.design.widget.TextInputLayout
    android:id="@+id/firstNameTextInputLayout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="8dp">

  <EditText
      android:id="@+id/firstNameEditText"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:hint="@string/first_name"
      android:inputType="textCapWords"
      android:textColor="@color/textPrimary"
      android:textColorHint="@color/textSecondary"
      android:textSize="16sp"
      android:theme="@style/CustomEditText"
      android:text=" "/>
</android.support.design.widget.TextInputLayout>