24

TextInputLayout содержит EditText, который, в свою очередь, получает вход от пользователя. С TextInputLayout, представленным в Библиотеке поддержки дизайна Android, мы должны установить ошибку в TextInputLayout, где находится EditText, а не сам EditText. При написании пользовательского интерфейса будет сфокусирован только на EditText, а не на весь TextInputLayout, который может привести к клавиатуре, покрывающей ошибку. В следующем уведомлении GIF пользователь должен сначала удалить клавиатуру, чтобы увидеть сообщение об ошибке. Это в сочетании с настройкой действий IME для перемещения по клавиатуре приводит к действительно запутывающим результатам.Текст ошибки в TextInputLayout покрыт клавиатурой

example error

код макета XML:

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

    <EditText 
     android:id="@+id/uid_edit_text" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:singleLine="true" 
     android:hint="Cardnumber" 
     android:imeOptions="actionDone"/> 

</android.support.design.widget.TextInputLayout> 

Java устанавливая ошибку в TextInputLayout код:

uidTextInputLayout.setError("Incorrect cardnumber"); 

Как я могу убедиться, что сообщение об ошибке отображается без пользовательского действия чтобы увидеть это? Можно ли переместить фокус?

+0

Думаю, вы должны подать отчет об ошибке [здесь] (https://code.google.com/p/android/issues/list). – natario

+1

Просто сделал это сейчас @mvai https://code.google.com/p/android/issues/detail?id=178153&thanks=178153&ts=1435245051 – Franzaine

+0

Я согласен с вами, хорошо поймать (и удачи). – natario

ответ

2

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

<ScrollView 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" > 

    <LinearLayout 
     android:layout_width="fill_parent" 
     android:layout_height="fill_parent" 
     android:orientation="vertical" > 
     ... 
     other views 
     ... 
    </LinearLayout> 
</ScrollView> 
+1

Пока он делает доступ к ошибке, он не показывает ошибку, не зная об этом пользователя и ищет его. Это с точки зрения UX требование, и я буду обновлять вопрос, чтобы это отразить. Спасибо за Ваш ответ! – Franzaine

+0

Согласен, но вы должны дать пользователю, по крайней мере, возможность увидеть сообщение об ошибке. – netpork

-1

Я просто выяснить, что если вы положите контейнер в фиксированную высоту, оставьте пространство клавиатуры для текста ошибки

<FrameLayout 
    android:layout_width="match_parent" 
    android:layout_height="75dp" 
    android:layout_alignParentBottom="true"> 

    <android.support.design.widget.TextInputLayout 
    android:id="@+id/text_layout" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:layout_gravity="center_horizontal" 
    app:errorEnabled="true" 
    app:errorTextAppearance="@style/ErrorText"> 

    <EditText 
     android:id="@+id/editText" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:imeOptions="actionGo" 
     android:inputType="textPersonName" 
     android:singleLine="true" /> 
    </android.support.design.widget.TextInputLayout> 
</FrameLayout> 
+1

Из атрибута «android: layout_alignParentBottom» в FrameLayout Я предполагаю, что вы делаете добавление «нижней панели» с TextInputLauout. При изменении размера окна с помощью клавиатуры это приводит к тому, что весь FrameLayout будет двигаться вверх. Это поведение НЕ связано с вопросом и объясненной проблемой вообще. – GuillermoMP

2

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

enter image description here

/** 
* [TextInputLayout] subclass that handles error messages properly. 
*/ 
class SmartTextInputLayout @JvmOverloads constructor(
     context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 
) : TextInputLayout(context, attrs, defStyleAttr) { 

    private val scrollView by lazy { findParentOfType<ScrollView>() } 
    private val nestedScrollView by lazy { findParentOfType<NestedScrollView>() } 

    private fun scrollIfNeeded() { 
     // Wait a bit (like 10 frames) for other UI changes to happen 
     postDelayed({ 
      scrollView?.scrollDownTo(this) 
      nestedScrollView?.scrollDownTo(this) 
     }, 160) 
    } 

    override fun setError(error: CharSequence?) { 
     super.setError(error) 

     // work around https://stackoverflow.com/q/34242902/1916449 
     isErrorEnabled = error != null 

     // work around https://stackoverflow.com/q/31047449/1916449 
     scrollIfNeeded() 
    } 
} 

Вот вспомогательные методы:

private inline fun <reified T> View.findParentOfType(): T? { 
    var p = parent 
    while (p != null && p !is T) p = p.parent 
    return p as T? 
} 

private fun ScrollView.scrollDownTo(descendant: View) { 
    howFarDownIs(descendant)?.let { smoothScrollBy(0, it) } 
} 

private fun NestedScrollView.scrollDownTo(descendant: View) { 
    howFarDownIs(descendant)?.let { smoothScrollBy(0, it) } 
} 

/** 
* Calculate how many pixels below the visible portion of [this] layout is the 
* bottom of [descendant]. 
* 
* In other words, how much you need to scroll down, to make [descendant]'s bottom 
* visible. 
*/ 
private fun FrameLayout.howFarDownIs(descendant: View): Int? { 
    return Rect().also { 
     // See https://stackoverflow.com/a/36740277/1916449 
     descendant.getDrawingRect(it) 
     offsetDescendantRectToMyCoords(descendant, it) 
    }.bottom.minus(height).minus(scrollY).takeIf { it > 0 } 
} 

Я также фиксированные TextInputLayout.setError() leaves empty space after clearing the error в том же классе.

0

Это Hacky, но вот то, что я сделал, чтобы обойти эту проблему:

Так как в этом случае мой TextInputLayout/EditText комбо жить в RecyclerView, я просто выделите ее, когда я установил ошибку:

textInputLayout.setError(context.getString(R.string.error_message)) 
recyclerView.scrollBy(0, context.convertDpToPixel(24f)) 

Он работает, но определенно не идеален. Было бы здорово, если бы Google исправил это, так как это определенно ошибка.

Смежные вопросы