在数据绑定中使用键盘上的完成按钮

Use Done button on Keyboard in Databinding

我正在尝试使用软键盘的完成按钮通过数据绑定激活方法。就像点击一样。有办法吗?

示例:

<EditText               
    android:id="@+id/preSignUpPg2EnterPhone"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"       
    onOkInSoftKeyboard="@{(v) -> viewModel.someMethod()}"
    />

onOkInSoftKeyboard 不存在...是否有创建此行为的方法?

谢谢!

我不会自称是 onEditorAction() 或软键盘方面的专家。也就是说,假设您使用 Firoz Memon 建议的堆栈溢出问题的解决方案,您可以实现它。即使有其他更好的解决方案,这也可以让您了解如何添加自己的事件处理程序。

您需要一个采用某种处理程序的绑定适配器。假设您有一个像这样的空监听器:

public class OnOkInSoftKeyboardListener {
    void onOkInSoftKeyboard();
}

那么你需要一个BindingAdapter:

@BindingAdapter("onOkInSoftKeyboard") // I like it to match the listener method name
public static void setOnOkInSoftKeyboardListener(TextView view,
        final OnOkInSoftKeyboardListener listener) {
    if (listener == null) {
        view.setOnEditorActionListener(null);
    } else {
        view.setOnEditorActionListener(new OnEditorActionListener() {
            @Override
            public void onEditorAction(TextView v, int actionId, KeyEvent event) {
                // ... solution to receiving event
                if (somethingOrOther) {
                    listener.onOkInSoftKeyboard();
                }
            }
        });
    }
}

正如我自己看到的那样,这是一个更简单的版本,其中直接从数据绑定调用该函数:

在您的 ViewModel 中使用此函数:

 public boolean onEditorAction(TextView view, int actionId, KeyEvent event) {
return false; // if you want the default action of the actionNext or so on
return true; // if you want to intercept
}

并且在布局中:

android:onEditorAction="@{(view,actionId,event) -> viewModel.onEditorAction(view,actionId,event)}"

使用 Kotlin,kapt 产生:

e: [kapt] An exception occurred: android.databinding.tool.util.LoggedErrorException: Found data binding errors.
****/ data binding error ****msg:Listener class kotlin.jvm.functions.Function1 with method invoke did not match signature of any method viewModel::signIn

(因为viewModel::signInKFunction1类型)所以我们不能使用方法引用。但是,如果我们在 viewModel 中创建一个明确类型的变量,那么我们可以将该变量作为绑定的参数传递。 (或者只使用 class)

Bindings.kt:

@BindingAdapter("onEditorEnterAction")
fun EditText.onEditorEnterAction(f: Function1<String, Unit>?) {

    if (f == null) setOnEditorActionListener(null)
    else setOnEditorActionListener { v, actionId, event ->

        val imeAction = when (actionId) {
            EditorInfo.IME_ACTION_DONE,
            EditorInfo.IME_ACTION_SEND,
            EditorInfo.IME_ACTION_GO -> true
            else -> false
        }

        val keydownEvent = event?.keyCode == KeyEvent.KEYCODE_ENTER 
            && event.action == KeyEvent.ACTION_DOWN

        if (imeAction or keydownEvent)
            true.also { f(v.editableText.toString()) }
        else false
    }
}

MyViewModel.kt:

fun signIn(password: String) {
    Toast.makeText(context, password, Toast.LENGTH_SHORT).show()
}

val signIn: Function1<String, Unit> = this::signIn

layout.xml:

<EditText
    android:id="@+id/password"
    app:onEditorEnterAction="@{viewModel.signIn}"
    android:imeOptions="actionDone|actionSend|actionGo"
    android:singleLine="true"/>

您可以通过对 Edittext 实施 setOnEditorActionListener 来直接调用 ViewModel 中的登录方法,参考 binging class

loginFragmentBinding.etPassword.setOnEditorActionListener(TextView.OnEditorActionListener { _, actionId, _ ->
        if (actionId == EditorInfo.IME_ACTION_DONE) {
            loginViewModel.login()
            return@OnEditorActionListener true
        }
        false
    })

Android 框架已经实现了这个。看看TextViewBindingAdapter

您会看到这些属性,the documentation 有点掩盖了这意味着什么,但简而言之:

  • attribute = 当此属性出现在布局文件中时
  • type = 然后在这个 class
  • 中寻找实现
  • method = 在类型
  • 中定义的 class 中具有此名称的方法

有关此的更多信息,请查看 this blog post

Kotlin,无需编写自定义绑定适配器

在布局中,

<EditText
    ...
    android:onEditorAction="@{(view, actionId, event) -> viewModel.onDoneClicked(view, actionId, event)}" />

视图模型

fun onDoneClicked(view: View, actionId: Int, event: KeyEvent?): Boolean {
    if(actionId == EditorInfo.IME_ACTION_DONE) {
        // handle here
        return true
    }
    return false
}

注意: event 可以为空,因此通过将 ? 放在那里使 KeyEvent 可以为空。