24

TextInputLayout contiene un EditText che a sua volta riceve l'input dall'utente. Con TextInputLayout introdotto con la libreria di supporto di Android Design, dovremmo impostare l'errore su TextInputLayout tenendo premuto EditText anziché EditText stesso. Quando si scrive l'interfaccia utente si concentrerà solo su EditText e non sull'intero TextInputLayout che può portare alla tastiera a coprire l'errore. Nel seguente avviso GIF, l'utente deve rimuovere prima la tastiera per visualizzare il messaggio di errore. Questo in combinazione con l'impostazione di azioni IME per passare all'utilizzo della tastiera porta a risultati davvero confusi.Il testo di errore in TextInputLayout è coperto dalla tastiera

example error

codice di layout 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> 

codice Java impostando l'errore al TextInputLayout:

uidTextInputLayout.setError("Incorrect cardnumber"); 

Come posso essere sicuro che il messaggio di errore è visibile senza che l'utente recitazione per vederlo? È possibile spostare la messa a fuoco?

+0

Penso che dovresti presentare una segnalazione di bug [qui] (https://code.google.com/p/android/issues/list). – natario

+1

L'ho appena fatto ora @mvai https://code.google.com/p/android/issues/detail?id=178153&thanks=178153&ts=1435245051 – Franzaine

+0

Sono d'accordo con te, buona cattura (e buona fortuna). – natario

risposta

2

È necessario inserire tutto nel contenitore ScrollView in modo che l'utente possa almeno scorrere e visualizzare il messaggio di errore. Questa è l'unica cosa che ha funzionato per me.

<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

Mentre effettua l'accesso all'errore possibile, non mostra l'errore senza che l'utente se ne accorga e lo cerchi. Questo è da un punto di vista UX un requisito e aggiornerò la domanda per riflettere questo. Grazie per la tua risposta! – Franzaine

+0

Sono d'accordo ma dovresti dare all'utente, almeno, la possibilità di vedere il messaggio di errore. – netpork

-1

ho appena scoperto che se si mette il recipiente in altezza fissa, tastiera lasciano spazio per il testo di errore

<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

Dall'attributo "android: layout_alignParentBottom" nel FrameLayout, immagino che quello che stai facendo sia aggiungere una "barra in basso" con TextInputLauout. Quando la finestra viene ridimensionata dalla tastiera, l'intero FrameLayout si sposta verso l'alto. Questo comportamento NON è correlato alla domanda e al problema illustrato. – GuillermoMP

2

per assicurarsi che il messaggio di errore è visibile senza che l'utente agisce a vederlo, mi sottoclasse TextInputLayout e lo ha inserito all'interno di un ScrollView. Questo mi consente di scorrere verso il basso se necessario per rivelare il messaggio di errore, in ogni occasione viene impostato il messaggio di errore. Non ci sono cambiamenti necessari nella classe activity/framment che lo usa.

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

Qui ci sono i metodi di supporto:

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

ho anche fissato TextInputLayout.setError() leaves empty space after clearing the error nella stessa classe.

0

E 'hacky ma qui è quello che ho fatto per ovviare a questo:

Poiché in questo caso il mio combo TextInputLayout/EditText vivere all'interno di un RecyclerView, ho semplicemente scorrere in su quando ho impostato l'errore:

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

Funziona, ma è decisamente meno ideale. Sarebbe bello se Google aggiustasse questo, dato che è sicuramente un bug.