Como lidar com o clique no botão concluído do ImeOptions?

185

Estou tendo um EditTextonde estou definindo a propriedade a seguir para que eu possa exibir o botão concluído no teclado quando o usuário clicar no EditText.

editText.setImeOptions(EditorInfo.IME_ACTION_DONE);

Quando o usuário clica no botão Concluído no teclado da tela (digitação concluída), desejo alterar um RadioButtonestado.

Como posso rastrear o botão Concluído quando ele é pressionado no teclado da tela?

Captura de tela mostrando o botão "pronto" no canto inferior direito do teclado do software

d-man
fonte
1
pode ser OnKeyboardActionListener me ajudar algum exemplo de código?
d-man

Respostas:

210

Acabei com uma combinação de Roberts e chirags respostas:

((EditText)findViewById(R.id.search_field)).setOnEditorActionListener(
        new EditText.OnEditorActionListener() {
    @Override
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
        // Identifier of the action. This will be either the identifier you supplied,
        // or EditorInfo.IME_NULL if being called due to the enter key being pressed.
        if (actionId == EditorInfo.IME_ACTION_SEARCH
                || actionId == EditorInfo.IME_ACTION_DONE
                || event.getAction() == KeyEvent.ACTION_DOWN
                && event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
            onSearchAction(v);
            return true;
        }
        // Return true if you have consumed the action, else false.
        return false;
    }
});

Atualização: o código acima algumas vezes ativaria o retorno de chamada duas vezes. Em vez disso, optei pelo código a seguir, obtido dos clientes de bate-papo do Google:

public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
    // If triggered by an enter key, this is the event; otherwise, this is null.
    if (event != null) {
        // if shift key is down, then we want to insert the '\n' char in the TextView;
        // otherwise, the default action is to send the message.
        if (!event.isShiftPressed()) {
            if (isPreparedForSending()) {
                confirmSendMessageIfNeeded();
            }
            return true;
        }
        return false;
    }

    if (isPreparedForSending()) {
        confirmSendMessageIfNeeded();
    }
    return true;
}
Thomas Ahle
fonte
4
Eu apenas procurei por IME_ACTION_DONE e fiquei surpreso por não ter sido acionado. Depois que eu também procurei por ACTION_DOWN e KEYCODE_ENTER, ele finalmente acionou onEditorAction (). Como não vejo diferença no teclado interno (esperava que a tecla Enter fosse destacada), pergunto-me qual é o sentido de usar o android: imeOptions = "actionSend" para o layout XML EditText.
Alguém em algum lugar
por que essa resposta não é aceita? isso falha em alguns casos?
usar o seguinte comando
1
developer.android.com/reference/android/widget/... (Descrição do que um 'evento' é afirma mesmos.)
Darpan
2
A segunda solução também é acionada duas vezes.
precisa saber é o seguinte
1
O que é isPreparedForSending()e por que o segundo método retorna true?
CoolMind 2/10
122

Tente isso, ele deve funcionar para o que você precisa:


editText.setOnEditorActionListener(new EditText.OnEditorActionListener() {
    @Override
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
    if (actionId == EditorInfo.IME_ACTION_DONE) {
       //do here your stuff f
       return true;
    }
    return false;
    } 
});
chikka.anddev
fonte
10
Isso não funciona para o HTC Evo. Tanto quanto pude entender, a HTC implementou seu próprio teclado virtual que ignora as imeOptions.
Dan
Isso é suficiente (não é necessário olhar para a ação do evento ou o código-chave, como na resposta aceita); funciona nos meus dispositivos de teste Nexus e Samsung.
Jonik
apenas para ser seguro, certifique-se de ação no código ea vista partidas <EditText android:imeOptions="actionDone" android:inputType="text"/>
bh_earth0
40
<EditText android:imeOptions="actionDone"
          android:inputType="text"/>

O código Java é:

edittext.setOnEditorActionListener(new OnEditorActionListener() { 
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
        if (actionId == EditorInfo.IME_ACTION_DONE) {
            Log.i(TAG,"Here you can write the code");
            return true;
        }    
        return false;
    }
});
Vinoj Vetha
fonte
Você deve retornar verdadeiro no caso cláusula para dizer que você lidou com isso
Tim Kist
26

Sei que essa pergunta é antiga, mas quero destacar o que funcionou para mim.

Tentei usar o código de exemplo no site Android Developers (mostrado abaixo), mas não funcionou. Portanto, verifiquei a classe EditorInfo e percebi que o valor inteiro IME_ACTION_SEND foi especificado como 0x00000004.

Código de exemplo de desenvolvedores do Android:

editTextEmail = (EditText) findViewById(R.id.editTextEmail);
editTextEmail
        .setOnEditorActionListener(new OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView v, int actionId,
                    KeyEvent event) {
                boolean handled = false;
                if (actionId == EditorInfo.IME_ACTION_SEND) {
                    /* handle action here */
                    handled = true;
                }
                return handled;
            }
        });

Então, adicionei o valor inteiro ao meu res/values/integers.xmlarquivo.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <integer name="send">0x00000004</integer>
</resources>

Em seguida, editei meu arquivo de layout da res/layouts/activity_home.xmlseguinte maneira

<EditText android:id="@+id/editTextEmail"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:imeActionId="@integer/send"
  android:imeActionLabel="@+string/send_label"
  android:imeOptions="actionSend"
  android:inputType="textEmailAddress"/>

E então, o código de exemplo funcionou.

iRuth
fonte
17

Mais detalhes sobre como definir o OnKeyListener e solicitá-lo ao botão Concluído.

Primeiro adicione OnKeyListener à seção de implementos da sua classe. Em seguida, adicione a função definida na interface OnKeyListener:

/*
 * Respond to soft keyboard events, look for the DONE press on the password field.
 */
public boolean onKey(View v, int keyCode, KeyEvent event)
{
    if ((event.getAction() == KeyEvent.ACTION_DOWN) &&
        (keyCode == KeyEvent.KEYCODE_ENTER))
    {
        // Done pressed!  Do something here.
    }
    // Returning false allows other listeners to react to the press.
    return false;
}

Dado um objeto EditText:

EditText textField = (EditText)findViewById(R.id.MyEditText);
textField.setOnKeyListener(this);
Robert Hawkey
fonte
2
Isso não funciona mais em aplicações dirigidas nível API 17+, porque o seu OnKeyListener não é acionado para eventos-chave moles: developer.android.com/reference/android/text/method/...
JJB
Eles sugerem uma alternativa agora?
precisa
2
Eu mudei para usar setOnEditorActionListener para procurar por EditorInfo.IME_ACTION_DONE, que parece funcionar bem.
JJB
onKey deve retornar verdadeiro, não falso.
Ralphgabb
16

Embora a maioria das pessoas tenha respondido diretamente à pergunta, eu queria elaborar mais sobre o conceito por trás dela. Primeiro, fui atraído pela atenção do IME quando criei uma atividade de logon padrão. Ele gerou um código para mim, que incluía o seguinte:

<EditText
  android:id="@+id/password"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:hint="@string/prompt_password"
  android:imeActionId="@+id/login"
  android:imeActionLabel="@string/action_sign_in_short"
  android:imeOptions="actionUnspecified"
  android:inputType="textPassword"
  android:maxLines="1"
  android:singleLine="true"/>

Você já deve estar familiarizado com o atributo inputType. Isso apenas informa ao Android o tipo de texto esperado, como endereço de e-mail, senha ou número de telefone. A lista completa de valores possíveis pode ser encontrada aqui .

Foi, no entanto, o atributo imeOptions="actionUnspecified"que eu não entendi seu propósito. O Android permite que você interaja com o teclado que aparece na parte inferior da tela quando o texto é selecionado usando o InputMethodManager. No canto inferior do teclado, há um botão, normalmente diz "Próximo" ou "Concluído", dependendo do campo de texto atual. O Android permite que você personalize isso usando android:imeOptions. Você pode especificar um botão "Enviar" ou um botão "Avançar". A lista completa pode ser encontrada aqui .

Com isso, você pode ouvir pressionamentos no botão de ação, definindo a TextView.OnEditorActionListenerpara o EditTextelemento. Como no seu exemplo:

editText.setOnEditorActionListener(new EditText.OnEditorActionListener() {
    @Override
    public boolean onEditorAction(EditText v, int actionId, KeyEvent event) {
    if (actionId == EditorInfo.IME_ACTION_DONE) {
       //do here your stuff f
       return true;
    }
    return false;
    } 
});

Agora, no meu exemplo, eu tinha android:imeOptions="actionUnspecified"atributo. Isso é útil quando você deseja tentar acessar um usuário quando ele pressiona a tecla Enter. Na sua atividade, você pode detectar essa tag e tentar o login:

    mPasswordView = (EditText) findViewById(R.id.password);
    mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
        @Override
        public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {
            if (id == R.id.login || id == EditorInfo.IME_NULL) {
                attemptLogin();
                return true;
            }
            return false;
        }
    });
Donato
fonte
6

Graças a chikka.anddev e Alex Cohn em Kotlin, é:

text.setOnEditorActionListener { v, actionId, event ->
    if (actionId == EditorInfo.IME_ACTION_DONE ||
        event?.action == KeyEvent.ACTION_DOWN && event.keyCode == KeyEvent.KEYCODE_ENTER) {
        doSomething()
        true
    } else {
        false
    }
}

Aqui, verifico a Enterchave, pois ela retorna em EditorInfo.IME_NULLvez de IME_ACTION_DONE.

Consulte também Android imeOptions = "actionDone" não está funcionando . Adicione android:singleLine="true"no EditText.

CoolMind
fonte
6

Solução Kotlin

A maneira básica de lidar com isso no Kotlin é:

edittext.setOnEditorActionListener { _, actionId, _ ->
    if (actionId == EditorInfo.IME_ACTION_DONE) {
        callback.invoke()
        true
    }
    false
}

Extensão Kotlin

Use isso apenas para chamar edittext.onDone{/*action*/}seu código principal. Torna seu código muito mais legível e sustentável

fun EditText.onDone(callback: () -> Unit) {
    setOnEditorActionListener { _, actionId, _ ->
        if (actionId == EditorInfo.IME_ACTION_DONE) {
            callback.invoke()
            true
        }
        false
    }
}

Não se esqueça de adicionar essas opções ao seu edittext

<EditText ...
    android:imeOptions="actionDone"
    android:inputType="text"/>

Se você precisar de inputType="textMultiLine"suporte, leia esta postagem

Gibolt
fonte
1
Ótima resposta, obrigado por compartilhar! Parece que eu continuo recebendo um aviso sobre o valor de retorno do setOnEditorActionListener. Talvez seja apenas uma questão de definições de configuração locais, mas meu linter realmente, realmente quer me adicionar um elseramo muito, a fim de aceitar a "verdade" como uma instrução de retorno do ouvinte (em oposição ao if-bloco).
dbm
0

Se você usa as Anotações do Android https://github.com/androidannotations/androidannotations

Você pode usar a anotação @EditorAction

@EditorAction(R.id.your_component_id)
void onDoneAction(EditText view, int actionId){
    if(actionId == EditorInfo.IME_ACTION_DONE){
        //Todo: Do your work or call a method
    }
}
Rafael Rocha
fonte