24

TextInputLayout zawiera EditText, który z kolei otrzymuje dane wejściowe od użytkownika. Wprowadzając TextInputLayout z biblioteką wsparcia Android Design, powinniśmy ustawić błąd w TextInputLayout trzymając EditText zamiast samego EditText. Podczas pisania interfejsu użytkownika będzie skupiać się tylko na EditText, a nie na całej operacji TextInputLayout, która może prowadzić do klawiatury opisującej błąd. W poniższym GIF zauważyć, że użytkownik musi najpierw usunąć klawiaturę, aby zobaczyć komunikat o błędzie. To w połączeniu z ustawianiem działań IME do poruszania się za pomocą klawiatury prowadzi do naprawdę mylących wyników.Tekst błędu w TextInputLayout jest objęty przez klawiaturę

example error

Kod Układ 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> 

kod Java ustawienie błąd w TextInputLayout:

uidTextInputLayout.setError("Incorrect cardnumber"); 

Jak mogę upewnić się, że komunikat jest widoczny bez aktorstwa użytkownika zobaczyć? Czy można przesunąć fokus?

+0

Myślę, że powinieneś złożyć raport o błędzie [tutaj] (https://code.google.com/p/android/issues/list). – natario

+1

Po prostu zrobiłem to teraz @mvai https://code.google.com/p/android/issues/detail?id=178153&thanks=178153&ts=1435245051 – Franzaine

+0

Zgadzam się z tobą, dobry połów (i powodzenia). – natario

Odpowiedz

2

Należy umieścić wszystko w kontenerze ScrollView, aby użytkownik mógł przynajmniej przewinąć i wyświetlić komunikat o błędzie. To jest jedyna rzecz, która zadziałała dla mnie.

<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

Mimo że umożliwia uzyskanie dostępu do błędu, nie wyświetla błędu, jeśli użytkownik o tym nie wie i nie szuka go. Jest to z punktu widzenia UX wymaganie i zaktualizuję pytanie, aby to odzwierciedlić. Dzięki za odpowiedź! – Franzaine

+0

Zgadzam się, ale powinieneś dać użytkownikowi co najmniej możliwość wyświetlenia komunikatu o błędzie. – netpork

-1

po prostu dowiedzieć się, że jeśli umieścić pojemnik w stałej wysokości, przestrzeni urlopu klawiatury tekst błędu

<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

Z "android: layout_alignParentBottom" atrybut w FrameLayout Myślę, że to, co robisz, jest dodanie "dolny pasek" z TextInputLauout. Kiedy rozmiar okna zmienia się za pomocą klawiatury, cały frameLayout przesuwa się w górę. To zachowanie NIE jest w ogóle związane z pytaniem i wyjaśnionym problemem. – GuillermoMP

2

Aby upewnić się, że komunikat jest widoczny bez użytkownika działającego go zobaczyć, ja podklasował TextInputLayout i umieścił go wewnątrz ScrollView. To pozwala mi przewinąć w dół, jeśli jest to konieczne, aby odsłonić komunikat o błędzie, za każdym razem, gdy ustawiony jest komunikat o błędzie. Nie ma żadnych zmian w klasie aktywności/fragmentów, które jej używają.

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() 
    } 
} 

Oto sposoby pomocnicze:

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 } 
} 

ja również trwałe TextInputLayout.setError() leaves empty space after clearing the error w tej samej klasie.

0

To hacky ale oto co zrobiłem, aby obejść ten problem:

Ponieważ w tym przypadku moja TextInputLayout/EditText kombi żyć w RecyclerView, po prostu wskaż go kiedy ustawić błąd:

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

Działa, ale zdecydowanie nie jest idealny. Byłoby wspaniale, gdyby Google to naprawił, ponieważ jest to z pewnością błąd.

Powiązane problemy