Kotlin addTextChangeListener lambda?


103

Làm cách nào để bạn tạo một biểu thức lambda cho EditText addTextChangeListener trong Kotlin? Dưới đây là một lỗi:

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

2
Nó đưa ra lỗi gì?
voddan

Câu trả lời:


244

addTextChangedListener()lấy a TextWatcherlà một giao diện với 3 phương thức. Những gì bạn đã viết sẽ chỉ hoạt động nếu TextWatcherchỉ có 1 phương pháp. Tôi sẽ đoán lỗi bạn gặp phải liên quan đến việc lambda của bạn không triển khai 2 phương pháp còn lại. Bạn có 2 lựa chọn trong tương lai.

  1. Bỏ lambda và chỉ sử dụng một lớp bên trong ẩn danh
    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. Tạo một phương thức mở rộng để bạn có thể sử dụng biểu thức 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())
          }
        })
    }

Và sau đó sử dụng tiện ích mở rộng như vậy:

editText.afterTextChanged { doSomethingWithText(it) }

4
Không chắc chắn nếu thích cá nhân hay phong cách tốt hơn, nhưng chức năng mở rộng của bạn có thể được chuyển đổi sang một cơ quan biểu thức ( fun foo() = ...)
F. George

6
@ mEQ5aNLrK3lqs3kfSa5HbvsTWe0nIu Bạn nói đúng rằng nó có thể được chuyển đổi. Tuy nhiên, đối với các hàm dài hơn một dòng, tôi muốn có các dấu ngoặc bao quanh để đánh dấu rõ ràng vị trí bắt đầu và dừng của hàm. Tôi tin rằng nó làm tăng khả năng đọc, nhưng nó hoàn toàn là một sở thích về phong cách. Tôi nghĩ rằng nó có thể được lập luận theo cả hai cách :)
Andrew Orobator

2
Không quan tâm: Tại sao gọi afterTextChanged.invoke(...)thay vì afterTextChanged(...)?
Felix D.

Điều này đã làm việc cho tôi. Tôi thích lựa chọn thứ 2 cho khả năng tái sử dụng.
Onie Maniego

21

Hơi cũ, nhưng bằng cách sử dụng các tiện ích mở rộng Kotlin Android, bạn có thể làm được những điều tương tự:

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

Không cần thêm mã, chỉ cần thêm:

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

4
Điều đó không hoạt động với tôi, ngay cả sau khi cấu trúc lại thành android X. Bạn có đoán được điều gì tôi có thể làm sai không?
Nícolas Schirmer

3
Không làm việc cho tôi là tốt. Có vẻ như KTX không cung cấp tiện ích mở rộng này nữa, tuy nhiên, KAndroid giải pháp hoạt động hoàn hảo.
Igor Wojda

2
với ktx: 1.0.1, bạn có thể sử dụng developer.android.com/reference/kotlin/androidx/core/widget/…
ingyesid

16

Thêm sự phụ thuộc ktx cốt lõi này

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

Bạn chỉ cần làm

passwordEditText.doAfterTextChanged{ }


12

hy vọng Kotlinmẫu này giúp làm cho nó rõ ràng:

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

Với XMLbố cục này :

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

Và điều này 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

Kiểm tra nó:

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

nếu bạn sử dụng implementation 'androidx.core:core-ktx:1.1.0-alpha05'bạn có thể sử dụng

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

Xin lỗi vì đến trễ!

Nếu bạn thêm implementation 'androidx.core:core-ktx:1.1.0'vào tệp build.gradle của mô-đun thì bạn có thể sử dụng

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

2

Một giải pháp thay thế khác là KAndroidthư viện -

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

Sau đó, bạn có thể làm một cái gì đó như thế này ...

editText.textWatcher { afterTextChanged { doSomething() } }

Rõ ràng là sử dụng toàn bộ thư viện để giải quyết vấn đề của bạn là quá mức, nhưng nó cũng đi kèm với một loạt các tiện ích mở rộng hữu ích khác giúp loại bỏ mã soạn sẵn trong Android SDK.


2

Bạn có thể sử dụng các tham số được đặt tên của 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

Thêm phụ thuộc ktx cốt lõi

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

Và bạn có thể đơn giản triển khai như thế này

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

-9

Điều này trông gọn gàng:

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

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

1
Tôi thực sự không biết với các bạn nhưng câu trả lời của tôi phù hợp với tôi và ngắn hơn câu trả lời ở trên và bên dưới ..
LEMUEL ADANE

1
Điều này hoạt động như những gì mã dự định, thực hiện hành động sau khi nhấn XONG. Tôi đã sửa đổi mã bằng cách đặt bánh mì nướng bên ngoài điều kiện và nó dường như chỉ kích hoạt khi nhấn TAB / DONE / etc. nhưng không phải trên các ký tự khác.
Onie Maniego
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.