web-dev-qa-db-fra.com

Center Hint et EditText verticalement dans TextInputLayout

J'utilise un TextInputLayout pour afficher un indice, mais je ne parviens pas à le centrer verticalement. Je reçois toujours ceci:

 enter image description here

Et je voudrais centrer l'indicateur verticalement lorsqu'il n'y a pas de texte dans EditText / TextInputEditText . J'ai essayé les idées de base (gravité, layout_gravity, etc.). Jusqu'ici, la seule façon de le faire serait d'ajouter un rembourrage "magique", mais j'aimerais le faire de manière plus propre. Je pensais mesurer la hauteur de l'étiquette de soupçon supérieure et l'ajouter comme marge inférieure lorsqu'elle n'est pas visible, et supprimer la même marge lorsqu'elle est visible, mais je ne comprends pas très bien le TextInputLayout code source . Est-ce que quelqu'un sait comment le faire?

Modifier:

J'ai essayé cette réponse suggérée:

<Android.support.design.widget.TextInputLayout
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    Android:layout_marginTop="20dp"
    Android:background="@color/grey_strong">

    <Android.support.design.widget.TextInputEditText
        Android:layout_width="match_parent"
        Android:layout_height="90dp"
        Android:background="@color/red_light"
        Android:gravity="center_vertical"
        Android:hint="Test"/>

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

Et je reçois ceci:

 enter image description here

Le "gros" indice n'est toujours pas centré verticalement. Il est un peu en dessous du centre car le "petit" indice (sur fond gris, en haut, visible uniquement lorsque le champ est mis au point) prend un peu de place en haut et pousse le EditText .

6
allo86

Cela ne semble pas être possible avec l'implémentation actuelle de TextInputLayout. Mais vous pouvez obtenir ce que vous voulez en jouant avec le rembourrage de la variable TextInputEditText.

Disons que vous avez une TextInputLayout et une TextInputEditText comme ceci:

<Android.support.design.widget.TextInputLayout
    Android:id="@+id/text_input_layout"
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    Android:background="#FAA"
    Android:hint="Text hint">

    <Android.support.design.widget.TextInputEditText
        Android:id="@+id/text_input_edit_text"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:background="#AAF" />

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

 enter image description here

 enter image description here

Comme vous pouvez le constater, la variable TextInputLayout se compose d’une zone supérieure pour contenir l’indice dans la version réduite et d’une zone inférieure pour contenir l’indicateur dans la version complète (et le contenu en entrée). Lorsque la vue perd le focus et que le texte de montage est vide, l'indicateur se déplace dans l'espace bleu. En revanche, lorsque la vue est mise en évidence ou que le texte modifié contient du texte, l’indice se déplace vers l’espace rouge.

Donc, ce que nous voulons faire, c'est:

  • ajoutez un remplissage supplémentaire au bas de la TextInputEditText lorsqu'elle ne contient pas de texte ni de focus, ce remplissage est égal à la hauteur de la zone rouge;
  • supprimez ce remplissage lorsque la TextInputEditText a le focus ou du texte à l'intérieur.

En conséquence, la vue ressemblera à ceci avec le gros indice centré verticalement:  enter image description here

Disons que vous récupérez vos points de vue comme suit:

private lateinit var textInputLayout: TextInputLayout
private lateinit var textInputEditText: TextInputEditText

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    ...
    textInputLayout = view.findViewById(R.id.text_input_layout)
    textInputEditText = view.findViewById(R.id.text_input_edit_text)
    ...
}

Voici un exemple d'implémentation que vous pouvez utiliser pour calculer l'espace rouge supérieur en pixels.

private fun getTextInputLayoutTopSpace(): Int {
    var currentView: View = textInputEditText
    var space = 0
    do {
        space += currentView.top
        currentView = currentView.parent as View
    } while (currentView.id != textInputLayout.id)
    return space
}

Ensuite, vous pouvez mettre à jour le remplissage comme ceci:

private fun updateHintPosition(hasFocus: Boolean, hasText: Boolean) {
    if (hasFocus || hasText) {
        textInputEditText.setPadding(0, 0, 0, 0)
    } else {
        textInputEditText.setPadding(0, 0, 0, getTextInputLayoutTopSpace())
    }
}

Vous devez maintenant appeler cette méthode à deux endroits: lorsque la vue est créée (en fait, nous devons attendre que la vue soit entièrement mesurée) et lorsque la mise au point change.

textInputLayout.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
    override fun onPreDraw(): Boolean {
        if (textInputLayout.height > 0) {
            textInputLayout.viewTreeObserver.removeOnPreDrawListener(this)
            updateHintPosition(textInputEditText.hasFocus(), !textInputEditText.text.isNullOrEmpty())
            return false
        }
        return true
    }
})

textInputEditText.setOnFocusChangeListener { _, hasFocus ->
    updateHintPosition(hasFocus, !textInputEditText.text.isNullOrEmpty())
}

Un problème est que la hauteur de la TextInputLayout est en train de changer, de sorte que toute la vue bouge et ne semble pas vraiment centrée. Vous pouvez résoudre ce problème en plaçant la TextInputLayout dans une FrameLayout avec une hauteur fixe et en la centrant verticalement.

Enfin, vous pouvez animer tout. Vous devez simplement utiliser la TransitionManager de la bibliothèque de support lorsque vous modifiez le remplissage.

Vous pouvez voir le résultat final dans ce lien: https://streamable.com/la9uk

Le code complet ressemblera à ceci:

La disposition:

<FrameLayout
    Android:layout_width="match_parent"
    Android:layout_height="60dp"> <-- Adapt the height for your needs -->

    <Android.support.design.widget.TextInputLayout
        Android:id="@+id/text_input_layout"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:layout_gravity="center_vertical"
        Android:background="#FAA"
        Android:hint="Text hint">

        <Android.support.design.widget.TextInputEditText
            Android:id="@+id/text_input_edit_text"
            Android:layout_width="match_parent"
            Android:layout_height="wrap_content"
            Android:background="#AAF" />

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

</FrameLayout>

Le code:

private lateinit var textInputLayout: TextInputLayout
private lateinit var textInputEditText: TextInputEditText

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    super.onCreateView(inflater, container, savedInstanceState)
    val view = inflater.inflate(R.layout.your_layout, container, false)

    textInputLayout = view.findViewById(R.id.text_input_layout)
    textInputEditText = view.findViewById(R.id.text_input_edit_text)

    textInputLayout.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
        override fun onPreDraw(): Boolean {
            // Wait for the first draw to be sure the view is completely measured
            if (textInputLayout.height > 0) {
                textInputLayout.viewTreeObserver.removeOnPreDrawListener(this)
                updateHintPosition(textInputEditText.hasFocus(), !textInputEditText.text.isNullOrEmpty(), false)
                return false
            }
            return true
        }
    })

    textInputEditText.setOnFocusChangeListener { _, hasFocus ->
        updateHintPosition(hasFocus, !textInputEditText.text.isNullOrEmpty(), true)
    }

    return view
}

private fun updateHintPosition(hasFocus: Boolean, hasText: Boolean, animate: Boolean) {
    if (animate) {
        TransitionManager.beginDelayedTransition(textInputLayout)
    }
    if (hasFocus || hasText) {
        textInputEditText.setPadding(0, 0, 0, 0)
    } else {
        textInputEditText.setPadding(0, 0, 0, getTextInputLayoutTopSpace())
    }
}

private fun getTextInputLayoutTopSpace(): Int {
    var currentView: View = textInputEditText
    var space = 0
    do {
        space += currentView.top
        currentView = currentView.parent as View
    } while (currentView.id != textInputLayout.id)
    return space
}

J'espère que cela résoudra votre problème.

4
JFrite

Veuillez utiliser ce code Si vous souhaitez afficher un indice EditText dans le centre

<Android.support.design.widget.TextInputLayout Android:layout_width="match_parent"
Android:layout_height="wrap_content"
xmlns:Android="http://schemas.Android.com/apk/res/Android">

<Android.support.design.widget.TextInputEditText
    Android:layout_width="match_parent"
    Android:layout_height="90dp"
    Android:hint="Test"
    Android:gravity="center" />

Si vous souhaitez afficher l’indice EditText au centre verticalement ainsi qu’à gauche

<Android.support.design.widget.TextInputLayout Android:layout_width="match_parent"
Android:layout_height="wrap_content"
xmlns:Android="http://schemas.Android.com/apk/res/Android">

<Android.support.design.widget.TextInputEditText
    Android:layout_width="match_parent"
    Android:layout_height="90dp"
    Android:hint="Test"
    Android:gravity="center_vertical" />

Ou 

<Android.support.design.widget.TextInputLayout Android:layout_width="match_parent"
Android:layout_height="wrap_content"
xmlns:Android="http://schemas.Android.com/apk/res/Android">

<Android.support.design.widget.TextInputEditText
    Android:layout_width="match_parent"
    Android:layout_height="90dp"
    Android:hint="Test"
    Android:gravity="center|left" />

1
Saurabh Vadhva

Trouvé une solution:

    <Android.support.design.widget.TextInputLayout
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content">

    <Android.support.design.widget.TextInputEditText
        Android:layout_width="200dp"
        Android:layout_height="90dp"
        Android:hint="Test"
        Android:gravity="center_vertical" />

90dp comme hauteur était juste à titre d'exemple. Si vous pouviez fournir votre code XML, je pourrais l'adapter à votre cas. Vous devez juste définir Android:gravity="center_vertical" et la TextInputLayout devrait avoir wrap_content comme hauteur

J'espère que ça aide :)

0
Rene Ferrari