Используйте кнопку Готово на клавиатуре в привязке данных

Я пытаюсь использовать кнопку «Готово» на мягкой клавиатуре, чтобы активировать метод через привязку данных. Прямо как onClick. Есть ли способ сделать это?

пример:

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

onOkInSoftKeyboard не существует ... Есть ли что-то для создания такого поведения?

Спасибо!


person Leandro Borges Ferreira    schedule 24.07.2017    source источник
comment
вы ищете что-то вроде stackoverflow.com/questions/2004344/ или что-то еще?   -  person Firoz Memon    schedule 24.07.2017
comment
Очевидно, что это что-то еще ... В представленном вами ответе не используется привязка данных, а используется прослушиватель. Я хочу, чтобы привязка данных активировала поведение. Пожалуйста, не голосуйте против, если вы действительно не уверены, что он дублируется.   -  person Leandro Borges Ferreira    schedule 24.07.2017
comment
Чтобы быть ясным, я НЕ ПРОТИВ голосовал за ваш вопрос ... и, привязав данные, что именно вы пытаетесь сделать, все еще неясно, не могли бы вы объяснить, чего вы пытаетесь достичь (также было бы лучше, если бы вы показали нам, что вы пробовали )   -  person Firoz Memon    schedule 24.07.2017
comment
Извини, Фироз, я не имел в виду тебя как проголосовавшего против ... Я просто говорил для всех, кто читает комментарий. Спасибо за попытку помочь мне в этом вопросе! Я обновил вопрос, чтобы было понятнее   -  person Leandro Borges Ferreira    schedule 24.07.2017


Ответы (6)


Я не буду называть себя экспертом в onEditorAction() или программной клавиатуре. Тем не менее, если вы используете решение вопроса о переполнении стека, которое предложил Фироз Мемон, вы можете это сделать. Даже если есть другое решение, которое работает лучше, это может дать вам представление о том, как добавить свои собственные обработчики событий.

Вам понадобится адаптер привязки, который требует какого-то обработчика. Предположим, у вас есть пустой слушатель вроде этого:

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();
                }
            }
        });
    }
}
person George Mount    schedule 24.07.2017
comment
Отличное решение! - person Leandro Borges Ferreira; 25.07.2017
comment
@LeandroBorgesFerreira, может полный код выложить сюда? Я получаю ошибки привязки данных при попытке реализовать это. - person mdb; 20.06.2018
comment
эй, как передать слушателя в xml - person skyshine; 31.12.2018
comment
это все шаблоны, которые вообще не нужны, если вы используете адаптер, созданный TextViewBindingAdapter.java - см. этот ответ stackoverflow.com/ a / 49375084/3175580 - person androidguy; 29.11.2019

Используя 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::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"/>
person ersin-ertan    schedule 20.10.2018
comment
Кроме того, вы можете использовать лямбда-выражение и удалить signIn Function1 из viewModle fun EditText.onEditorEnterAction (block: ((пароль: String) - ›Unit)?) {... block (password)} - person Omar Abdan; 21.10.2020
comment
@OmarAbdan, тогда как использовать эту функцию в XML? - person CoolMind; 10.06.2021
comment
Спасибо, это работает. Не забудьте удалить android:inputType="textMultiLine", может быть, установите android:maxLines="1" и android:singleLine="true". - person CoolMind; 10.06.2021
comment
Для многострочного текста см. stackoverflow.com/ вопросы / 2986387 /. - person CoolMind; 10.06.2021

Так же, как я сам смотрел на это, вот более простая версия, в которой функция вызывается напрямую из привязки данных:

В вашей 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)}"
person Tosa    schedule 20.03.2018
comment
Событие KeyEvent возвращает значение null! - person Sajad Rahmanipour; 22.04.2018
comment
неизвестный атрибут onEditorAction @Tosa - person hushed_voice; 09.05.2018
comment
он говорит, что в редакторе, но у меня он отлично работает, когда приложение запущено. @ free_style - person Tosa; 14.06.2018
comment
@Tosa, событие всегда равно null - person Sajad Rahmanipour; 18.06.2018
comment
@SajadRahmanipour, и он не равен нулю, когда вы реализуете слушателя, как из отмеченного ответа? developer.android.com/reference/android/widget/. - person Tosa; 19.06.2018
comment
Это правильно, поскольку он использует адаптеры, предоставляемые привязкой данных в TextViewBindingAdapter.java: `@BindingMethod (type = TextView.class, attribute = android: onEditorAction, method = setOnEditorActionListener)` - person androidguy; 29.11.2019
comment
Это не сработает: невозможно найти метод onEditorAction (android.widget.TextView, int, android.view.KeyEvent), потому что мы передаем EditText, а не TextView. Несмотря на то, что он расширяет TextView, он все равно терпит неудачу. - person DevinM; 23.01.2020

Kotlin, без написания адаптера пользовательской привязки

В макете,

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

ViewModel

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, указав здесь ?.

person gprathour    schedule 28.03.2021
comment
@AhmadAbdullah Для меня это сработало. Возможно, чего-то не хватает или есть другая проблема. - person gprathour; 21.05.2021
comment
Спасибо @gprathour, сработало, только что ошибся в типе возвращаемого значения функции - person Ahmad Abdullah; 23.05.2021
comment
@AhmadAbdullah Это хорошо знать. Ошибки, отображаемые для привязки данных, иногда бывают странными, и их нелегко понять, в чем именно заключается ошибка. Удачи! - person gprathour; 25.05.2021

Вы можете напрямую вызвать метод входа в ViewModel, реализовав setOnEditorActionListener в Edittext, взяв ссылку из класса binging

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

В платформе Android это уже реализовано. Взгляните на TextViewBindingAdapter

Вы увидите эти атрибуты, документацию как бы замалчивает, что это означает, но в двух словах:

  • attribute = когда этот атрибут появляется в файле макета
  • type = тогда ищите реализацию в этом классе
  • method = метода с этим именем в классе, определенном в типе

Подробнее об этом см. в этом сообщении в блоге.

person Filipe Bezerra de Sousa    schedule 20.01.2021