【问题标题】:Kotlin addTextChangeListener lambda?Kotlin addTextChangeListener lambda?
【发布时间】:2017-03-26 22:48:51
【问题描述】:

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

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

【问题讨论】:

  • 它给出了什么错误?
  • 您好,我认为我的问题已经过编辑以适合他的回答。

标签: android kotlin textview anko


【解决方案1】:

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

【讨论】:

  • 不确定是个人喜好还是更好的风格,但是您的扩展函数可以转换为表达式体(fun foo() = ...
  • @mEQ5aNLrK3lqs3kfSa5HbvsTWe0nIu 你说得对,它可以转换。但是,对于超过一行的函数,我喜欢用括号括起来以清楚地标记函数的开始和停止位置。我相信它增加了可读性,但这完全是一种风格偏好。我认为这可以双向争论:)
  • 出于兴趣:为什么打电话给afterTextChanged.invoke(...)而不是afterTextChanged(...)
  • 这对我有用。我更喜欢可重用性的第二个选项。
【解决方案2】:

添加这个核心ktx依赖

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

你只需要这样做

passwordEditText.doAfterTextChanged{ }

【讨论】:

    【解决方案3】:

    有点老了,但是使用 Kotlin Android 扩展你可以做这样的事情:

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

    不需要额外的代码,只需添加:

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

    【讨论】:

    • 这对我不起作用,即使在重构为 android X 之后也是如此。猜猜我可能做错了什么?
    • 对我也不起作用。看起来 KTX 不再提供此扩展,但是,KAndroid 解决方案完美运行。
    • implementation "androidx.core:core-ktx:1.2.0" -> edt.addTextChangedListener(afterTextChanged = { /*dosomething*/ })
    • 只使用 editTextRequest.doAfterTextChanged { ... } 更容易
    【解决方案4】:

    希望这个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
    

    【讨论】:

      【解决方案5】:

      测试一下:

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

      【讨论】:

        【解决方案6】:

        抱歉迟到了!

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

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

        【讨论】:

          【解决方案7】:

          如果你使用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

          【讨论】:

            【解决方案8】:

            添加核心ktx依赖

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

            你可以像这样简单地实现

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

            【讨论】:

              【解决方案9】:

              如果您使用材料 Filled text fieldOutlined text field,请尝试分别响应文档中提到的输入文本更改:

              filledTextField.editText?.doOnTextChanged { inputText, _, _, _ ->
                  // Respond to input text change
              }
              

              outlinedTextField.editText?.doOnTextChanged { inputText, _, _, _ ->
                  // Respond to input text change
              }
              

              【讨论】:

                【解决方案10】:

                另一种选择是KAndroid 库 -

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

                那么你可以做这样的事情......

                editText.textWatcher { afterTextChanged { doSomething() } }
                

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

                【讨论】:

                  【解决方案11】:

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

                  【讨论】:

                    【解决方案12】:

                    这看起来很整洁:

                    passwordEditText.setOnEditorActionListener { 
                        textView, keyCode, keyEvent ->
                        val DONE = 6
                    
                        if (keyCode == DONE) {                       
                             // your code here
                        }
                        false
                    }
                    

                    【讨论】:

                    • 我真的不知道你们,但我的答案对我有用,并且比上面和下面的答案短..
                    • 这按代码的意图工作,一旦按下 DONE 就会执行操作。我通过在条件之外放置一个 toast 来修改代码,它似乎只在按下 TAB/DONE/etc 时触发。但不适用于其他角色。
                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2018-11-28
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多