Kotlin addTextChangeListener lambda吗?


103

如何在Kotlin中为EditText addTextChangeListener构建lambda表达式?下面给出了一个错误:

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

2
它给出什么错误?
voddan

Answers:


244

addTextChangedListener()需要一个TextWatcher带有3个方法的接口。如果TextWatcher只有一种方法,则您编写的内容仅适用。我将猜测您得到的错误与您的lambda不实现其他两种方法有关。您有2种选择。

  1. 抛弃lambda,只使用一个匿名内部类
    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. 创建一个扩展方法,以便您可以使用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())
          }
        })
    }

然后像这样使用扩展名:

editText.afterTextChanged { doSomethingWithText(it) }

4
不知道是个人喜好还是更好的风格,但您的扩展功能是否可以转换为表情主体(fun foo() = ...
F. George

6
@ mEQ5aNLrK3lqs3kfSa5HbvsTWe0nIu您是对的,可以转换。但是,对于长于一行的函数,我喜欢用方括号清楚地标记函数的开始和停止位置。我相信它可以提高可读性,但这完全是样式偏好。我认为可以双向争论:)
Andrew Orobator

2
出于兴趣:为什么要致电afterTextChanged.invoke(...)而不是afterTextChanged(...)
Felix D.

这对我有用。对于可重用性,我更喜欢第二种选择。
Onie Maniego,

21

有点老了,但是使用Kotlin Android扩展,您可以执行以下操作:

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

无需额外的代码,只需添加:

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

4
即使对android X进行了重构,这对我也不起作用。我可能会做错什么的猜测吗?
尼古拉斯·希尔默

3
也不适合我。看起来KTX不再提供此扩展,但是,该 KAndroid 解决方案可以正常工作。
伊戈尔·沃达


16

添加此核心ktx依赖性

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

您只需要做

passwordEditText.doAfterTextChanged{ }


12

希望此Kotlin示例有助于清楚说明:

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

使用此XML布局:

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

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

测试一下:

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

如果您使用implementation 'androidx.core:core-ktx:1.1.0-alpha05'可以使用

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

对不起,来晚了!

如果添加implementation 'androidx.core:core-ktx:1.1.0'到模块的build.gradle文件中,则可以使用

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

2

另一种选择是KAndroid图书馆-

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

然后你可以做这样的事情...

editText.textWatcher { afterTextChanged { doSomething() } }

显然,使用整个库来解决您的问题是多余的,但是它还附带了一系列其他有用的扩展,这些扩展消除了Android SDK中的样板代码。


2

您可以使用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

添加核心ktx依赖项

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

您可以像这样简单地实现

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

-9

这看起来很整洁:

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

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

1
我真的不知道有你们,但我的回答为我工作比上面和下面的回答更短..
雷米尔ADANE

1
这与代码的意图相同,一旦按下DONE,便执行操作。我通过在条件之外放置祝酒词来修改了代码,似乎只有在按TAB / DONE / etc时才会触发。但其他字符除外。
Onie Maniego,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.