Kotlin addTextChangeListener lambda?


104

Comment créer une expression lambda pour le AddTextChangeListener EditText dans Kotlin? Ci-dessous donne une erreur:

passwordEditText.addTextChangedListener { charSequence  ->
    try {
        password = charSequence.toString()
    } catch (error: Throwable) {
        raise(error)
    }
}

2
Quelle erreur cela donne-t-il?
voddan

Réponses:


244

addTextChangedListener()prend un TextWatcherqui est une interface avec 3 méthodes. Ce que vous avez écrit ne fonctionnerait que si vous n'aviez qu'une TextWatcherseule méthode. Je vais deviner que l'erreur que vous obtenez est liée au fait que votre lambda n'implémente pas les 2 autres méthodes. Vous avez 2 options pour l'avenir.

  1. Abandonnez le lambda et utilisez simplement une classe interne anonyme
    editText.addTextChangedListener(object : TextWatcher {
      override fun afterTextChanged(s: Editable?) {
      }
    
      override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
      }
    
      override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
      }
    })
  1. Créez une méthode d'extension afin de pouvoir utiliser une expression lambda:
    fun EditText.afterTextChanged(afterTextChanged: (String) -> Unit) {
        this.addTextChangedListener(object : TextWatcher {
          override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
          }
    
          override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
          }
    
          override fun afterTextChanged(editable: Editable?) {
            afterTextChanged.invoke(editable.toString())
          }
        })
    }

Et puis utilisez l'extension comme ceci:

editText.afterTextChanged { doSomethingWithText(it) }

4
Je ne sais pas si vos préférences personnelles ou un meilleur style, mais votre fonction d'extension pourrait être convertie en un corps d'expression ( fun foo() = ...)
F. George

6
@ mEQ5aNLrK3lqs3kfSa5HbvsTWe0nIu Vous avez raison de dire qu'il peut être converti. Cependant, pour les fonctions de plus d'une ligne, j'aime avoir des parenthèses pour marquer clairement où la fonction commence et s'arrête. Je pense que cela augmente la lisibilité, mais c'est totalement une préférence de style. Je pense que cela pourrait être discuté dans les deux sens :)
Andrew Orobator

2
Par intérêt: pourquoi appeler afterTextChanged.invoke(...)au lieu de afterTextChanged(...)?
Felix D.

Cela a fonctionné pour moi. J'ai préféré la 2ème option pour la réutilisabilité.
Onie Maniego

21

Un peu vieux, mais en utilisant les extensions Android de Kotlin, vous pouvez faire quelque chose comme ça:

editTextRequest.textChangedListener {
            afterTextChanged {
                // Do something here...
            }
}

Aucun code supplémentaire nécessaire, ajoutez simplement:

implementation 'androidx.core:core-ktx:1.0.0'

4
Cela ne fonctionne pas pour moi, même après la refactorisation vers Android X. Une idée de ce que je pourrais faire de mal?
Nícolas Schirmer

3
Cela ne fonctionne pas non plus pour moi. Il semble que KTX ne fournit plus cette extension, cependant, la KAndroid solution fonctionne parfaitement.
Igor Wojda


16

Ajouter cette dépendance ktx principale

implementation 'androidx.core:core-ktx:1.0.0'

Vous devez simplement faire

passwordEditText.doAfterTextChanged{ }


12

J'espère que cet Kotlinexemple vous aidera à clarifier:

class MainFragment : Fragment() {

    private lateinit var viewModel: MainViewModel

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

    view.user.addTextChangedListener(object : TextWatcher {
        override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {

        }

        override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {

        }

        override fun afterTextChanged(s: Editable) {
                userLayout.error =
                        if (s.length > userLayout.counterMaxLength) {
                            "Max character length is: ${userLayout.counterMaxLength}"
                        } else null
        }
    })
    return view
}

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)
    viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
    // TODO: Use the ViewModel
   }
}

Avec cette XMLdisposition:

<android.support.design.widget.TextInputLayout
    android:id="@+id/userLayout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:counterMaxLength="5"
    app:counterEnabled="true"
    android:hint="user_name">

    <android.support.design.widget.TextInputEditText
        android:id="@+id/user"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</android.support.design.widget.TextInputLayout>

Et ceci Gradle:

android {
    compileSdkVersion 'android-P'
...
}
    api 'com.android.support:design:28.0.0-alpha1'

    implementation 'com.android.support:appcompat-v7:28.0.0-alpha1' // appcompat library

12

Essaye-le :

passwordEditText.addTextChangedListener(object:TextWatcher{override fun afterTextChanged(s: Editable?) {

    }

    override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
    }

    override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {

    }

})

10

si vous utilisez, implementation 'androidx.core:core-ktx:1.1.0-alpha05'vous pouvez utiliser

For android.widget.TextView
TextWatcher 
TextView.doBeforeTextChanged(crossinline action: (text: CharSequence?, start: Int, count: Int, after: Int) -> Unit)
Add an action which will be invoked before the text changed.

TextWatcher 
TextView.doOnTextChanged(crossinline action: (text: CharSequence?, start: Int, count: Int, after: Int) -> Unit)
Add an action which will be invoked when the text is changing.

TextWatcher 
TextView.doAfterTextChanged(crossinline action: (text: Editable?) -> Unit)

https://developer.android.com/reference/kotlin/androidx/core/widget/package-summary#extension-functions


4

Désolé d'être en retard!

Si vous ajoutez implementation 'androidx.core:core-ktx:1.1.0'au fichier build.gradle de votre module, vous pouvez utiliser

etPlayer1.doOnTextChanged { text, start, count, after -> // Do stuff }

2

Une autre alternative est la KAndroidbibliothèque -

implementation 'com.pawegio.kandroid:kandroid:0.8.7@aar'

Ensuite, vous pourriez faire quelque chose comme ça ...

editText.textWatcher { afterTextChanged { doSomething() } }

Évidemment, il est excessif d'utiliser une bibliothèque entière pour résoudre votre problème, mais il est également livré avec une gamme d'autres extensions utiles qui éliminent le code standard dans le SDK Android.


2

Vous pouvez utiliser les paramètres nommés de kotlin:

private val beforeTextChangedStub: (CharSequence, Int, Int, Int) -> Unit = { _, _, _, _ -> }
private val onTextChangedStub: (CharSequence, Int, Int, Int) -> Unit = { _, _, _, _ -> }
private val afterTextChangedStub: (Editable) -> Unit = {}

fun EditText.addChangedListener(
        beforeTextChanged: (CharSequence, Int, Int, Int) -> Unit = beforeTextChangedStub,
        onTextChanged: (CharSequence, Int, Int, Int) -> Unit = onTextChangedStub,
        afterTextChanged: (Editable) -> Unit = afterTextChangedStub
) = addTextChangedListener(object : TextWatcher {
    override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
        beforeTextChanged(charSequence, i, i1, i2)
    }

    override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
        onTextChanged(charSequence, i, i1, i2)
    }

    override fun afterTextChanged(editable: Editable) {
        afterTextChanged(editable)
    }
})

0

Ajouter la dépendance ktx principale

implementation 'androidx.core:core-ktx:1.3.0'

Et vous pouvez simplement mettre en œuvre comme ça

    edit_text.addTextChangedListener { it: Editable? ->
      // Do your stuff here
    }

-9

Cela a l'air bien:

passwordEditText.setOnEditorActionListener { 
    textView, keyCode, keyEvent ->
    val DONE = 6

    if (keyCode == DONE) {                       
         // your code here
    }
    false
}

1
Je ne sais vraiment pas avec vous les gars mais ma réponse a fonctionné pour moi et est plus courte que la réponse ci-dessus et ci-dessous ..
LEMUEL ADANE

1
Cela fonctionne comme ce que le code a l'intention d'être, effectue une action une fois que vous avez appuyé sur DONE. J'ai modifié le code en plaçant un toast en dehors de la condition et il semble ne se déclencher que lorsque vous appuyez sur TAB / DONE / etc. mais pas sur d'autres personnages.
Onie Maniego
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.