Kotlin addTextChangeListener lambda?

104

Bagaimana Anda membuat ekspresi lambda untuk EditText addTextChangeListener di Kotlin? Di bawah ini memberikan kesalahan:

passwordEditText.addTextChangedListener { charSequence  ->
    try {
        password = charSequence.toString()
    } catch (error: Throwable) {
        raise(error)
    }
}
LEMUEL ADANE
sumber
2
Kesalahan apa yang diberikannya?
voddan

Jawaban:

246

addTextChangedListener()mengambil TextWatcheryang merupakan antarmuka dengan 3 metode. Apa yang Anda tulis hanya akan berfungsi jika TextWatcherhanya memiliki 1 metode. Saya akan menebak kesalahan yang Anda dapatkan terkait dengan lambda Anda yang tidak menerapkan 2 metode lainnya. Anda memiliki 2 opsi untuk maju.

  1. Singkirkan lambda dan cukup gunakan kelas dalam anonim
    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. Buat metode ekstensi sehingga Anda dapat menggunakan ekspresi 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())
          }
        })
    }

Dan kemudian gunakan ekstensi seperti ini:

editText.afterTextChanged { doSomethingWithText(it) }
Andrew Orobator
sumber
4
Tidak yakin apakah preferensi pribadi atau gaya yang lebih baik, tetapi fungsi ekstensi Anda dapat dikonversi ke ekspresi tubuh ( fun foo() = ...)
F. George
6
@ mEQ5aNLrK3lqs3kfSa5HbvsTWe0nIu Anda benar bahwa ini dapat diubah. Namun, untuk fungsi yang lebih panjang dari satu baris, saya suka memiliki tanda kurung di sekitarnya untuk menandai dengan jelas di mana fungsi dimulai dan berhenti. Saya percaya ini meningkatkan keterbacaan, tetapi ini benar-benar preferensi gaya. Saya pikir itu bisa diperdebatkan dengan dua cara :)
Andrew Orobator
2
Di luar minat: Mengapa menelepon, afterTextChanged.invoke(...)bukan afterTextChanged(...)?
Felix D.
Ini berhasil untuk saya. Saya lebih suka opsi kedua karena dapat digunakan kembali.
Onie Maniego
21

Agak tua, tetapi menggunakan ekstensi Android Kotlin Anda dapat melakukan sesuatu seperti itu:

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

Tidak perlu kode tambahan, cukup tambahkan:

implementation 'androidx.core:core-ktx:1.0.0'
Efi MK
sumber
4
Itu tidak berhasil untuk saya, bahkan setelah refactoring ke android X. Ada tebakan apa yang bisa saya lakukan salah?
Nícolas Schirmer
3
Tidak bekerja untuk saya juga. Sepertinya KTX tidak menyediakan ekstensi ini lagi, namun KAndroid solusi bekerja dengan sempurna.
Igor Wojda
2
dengan ktx: 1.0.1 Anda dapat menggunakan developer.android.com/reference/kotlin/androidx/core/widget/…
ingyesid
17

Tambahkan ketergantungan inti ktx ini

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

Anda hanya perlu melakukannya

passwordEditText.doAfterTextChanged{ }

Alaa
sumber
12

harap Kotlincontoh ini membantu memperjelas:

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

Dengan XMLtata letak ini :

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

Dan ini 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
Hasan A Yousef
sumber
12

Menguji :

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) {

    }

})
Reza Khammary
sumber
10

jika Anda menggunakan implementation 'androidx.core:core-ktx:1.1.0-alpha05'Anda bisa menggunakan

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

ingyesid
sumber
4

Maaf saya terlambat!

Jika Anda menambahkan implementation 'androidx.core:core-ktx:1.1.0'file build.gradle modul Anda, maka Anda dapat menggunakan

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

Alternatif lain adalah KAndroidperpustakaan -

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

Maka Anda bisa melakukan sesuatu seperti ini ...

editText.textWatcher { afterTextChanged { doSomething() } }

Jelas berlebihan menggunakan seluruh pustaka untuk memecahkan masalah Anda, tetapi juga dilengkapi dengan berbagai ekstensi berguna lainnya yang menghilangkan kode boilerplate di Android SDK.

nsc9012
sumber
2

Anda dapat menggunakan parameter bernama 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)
    }
})
Dmitrii Bychkov
sumber
0

Tambahkan ketergantungan inti ktx

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

Dan Anda cukup menerapkan seperti ini

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

Ini terlihat rapi:

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

    if (keyCode == DONE) {                       
         // your code here
    }
    false
}
LEMUEL ADANE
sumber
1
Saya benar-benar tidak tahu dengan kalian tetapi jawaban saya berhasil untuk saya dan lebih pendek dari jawaban di atas dan di bawah ..
LEMUEL ADANE
1
Ini berfungsi seperti yang diinginkan kode, melakukan tindakan setelah SELESAI ditekan. Saya mengubah kode dengan bersulang di luar kondisi dan tampaknya hanya menyala ketika menekan TAB / DONE / etc. tapi tidak pada karakter lain.
Onie Maniego