Проблема с перекрытием подсказки 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>