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

时间:2017-07-24 18:53:55

标签: android android-databinding

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

示例:

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

onOkInSoftKeyboard不存在......有什么东西可以创造这种行为吗?

谢谢!

7 个答案:

答案 0 :(得分:10)

我不会声称自己是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();
                }
            }
        });
    }
}

答案 1 :(得分:3)

katlin使用Kotlin产生:

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::signIn的类型为KFunction1),所以我们不能使用方法引用。但是,如果我们在viewModel内创建一个关于类型的显式变量,则可以将该变量作为绑定的参数传递。 (或只使用一个类)

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

答案 2 :(得分:2)

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 可以为 null,因此通过将 KeyEvent 放在那里使 ? 可以为 null。

答案 3 :(得分:0)

您只需使用EditText动作完成事件。

    import java.io.File;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;

public class Demo {

    public static void main(String[] args) throws Exception {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();

        Document originalDocument = db.parse(new File("input.xml"));
        Node originalRoot = originalDocument.getDocumentElement();

        Document copiedDocument = db.newDocument();
        Node copiedRoot = copiedDocument.importNode(originalRoot, true);
        copiedDocument.appendChild(copiedRoot);

    }
}
<EditText
    android:id="@+id/preSignUpPg2EnterPhone"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:imeOptions="actionDone"
    />

答案 4 :(得分:0)

您可以通过实现setOnEditorActionListener到Edittext来直接调用loginModel在ViewModel内部的方法,并引用binging类

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

答案 5 :(得分:0)

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

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

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

有关这方面的更多信息,请查看 this blog post

答案 6 :(得分:-1)

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

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