EditText multilinha com botão de ação Concluído

114

É possível ter um EditTextwidget com android:inputType="textMultiLine"set, e android:imeOptions="actionDone"ao mesmo tempo?

Eu gostaria de uma caixa de edição de várias linhas, com o botão de ação no teclado concluído, não Enter (Retorno de carro), mas não parece estar funcionando.

desde já, obrigado

kefs
fonte
Que tal tentar um widget composto com EditText multilinha e um Button combinados?
Subin Sebastian

Respostas:

194

Usar

editText.setImeOptions(EditorInfo.IME_ACTION_DONE);
editText.setRawInputType(InputType.TYPE_CLASS_TEXT);

e em XML:

android:inputType="textMultiLine"
alexbtr
fonte
para mim, o cursor ainda seria mostrado quando o teclado abaixasse, eu precisava adicionar textField.setCursorVisible(false);dentro de umonEditorActionListener
Fonix
Funciona em 4.2.2 e 7.1.1. Obrigado.
tehcpu
1
Funciona muito bem ... Lutei para encontrá-lo. Esta resposta deve ser marcada como a melhor resposta
MFAL
7
por que isso funciona em oposição a configurar tudo em xml?
Andrew Steinmetz
1
Esforcei-me um pouco para encontrar essa informação. Ainda está funcionando como um encanto!
Costin
51

Da documentação do Android: ' "textMultiLine" Teclado de texto normal que permite aos usuários inserir longas cadeias de texto que incluem quebras de linha (retornos de carro) . 'Portanto, o atributo textMultiLine não é apropriado se você deseja ter o botão' Concluído 'no teclado.

Uma maneira simples de obter um campo de entrada de várias linhas (neste caso 3 linhas) com o botão concluído é usar EditText com

android:lines="3" 
android:scrollHorizontally="false" 

No entanto, por algum motivo, isso só funciona para mim se eu fizer essas configurações no código em vez do arquivo de layout (em onCreate) por

TextView tv = (TextView)findViewById(R.id.editText);
if (tv != null) {
    tv.setHorizontallyScrolling(false);
    tv.setLines(3);
}

Espero que isso ajude alguém, pois demorou um pouco para descobrir. Se você encontrar uma maneira de fazê-lo funcionar a partir do manifesto, informe-nos.

HYS
fonte
4
Também sugiro que tente, em maxLines()vez de, setLines()se quiser evitar alterar a altura doEditText
Daniel Smith
Acho que na pergunta não está esclarecido que você deve definir android: imeOptions com um valor como actionSend. Concluindo esta resposta, eu tive que definir android: singleLine = "true" mesmo se o setMaxLines meio que o sobrescreveu por código (não fazer isso não fornecerá uma tecla enter com, por exemplo, "Send"). Para capturar a ação <Enter>, verifique a primeira resposta em stackoverflow.com/questions/5014219/… out.
DNax 01 de
Desculpe, a melhor alternativa que encontrei para capturar o <Enter> é @earlcasper, responda aqui stackoverflow.com/questions/1489852/…
DNax
1
Isso funcionou perfeitamente para mim (usando setMaxLines(3)) Muito obrigado!
laurencevs
1
Funcionou perfeitamente: basta adicionar android: imeOptions = "actionDone" android: inputType = "text" ao seu XML e remover android: lines = "3" android: scrollHorizontally = "false" do XML
HannahCarney
24

Exemplo de trabalho! Crie a classe EditText personalizada abaixo que ofereça suporte a esse recurso e use a classe no arquivo xml. Código de trabalho:

package com.example;

import android.content.Context;
import android.util.AttributeSet;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.widget.EditText;

public class ActionEditText extends EditText
{
   public ActionEditText(Context context)
   {
       super(context);
   }

   public ActionEditText(Context context, AttributeSet attrs)
   {
       super(context, attrs);
   }

   public ActionEditText(Context context, AttributeSet attrs, int defStyle)
   {
       super(context, attrs, defStyle);
   }

   @Override
   public InputConnection onCreateInputConnection(EditorInfo outAttrs)
   {
       InputConnection conn = super.onCreateInputConnection(outAttrs);
       outAttrs.imeOptions &= ~EditorInfo.IME_FLAG_NO_ENTER_ACTION;
       return conn;
   }
}

<com.example.ActionEditText
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:imeOptions="actionDone"
       android:inputType="textAutoCorrect|textCapSentences|textMultiLine" />
Anees U
fonte
Isso funcionou para mim, meu requisito era fazer um texto de edição que deveria ser de várias linhas, bem como deveria ter o botão próximo nas teclas de função ............... então, muito obrigado pelo que fiz estava no texto de edição, adicionei 2 linhas android: inputType = "textMultiLine" android: imeOptions = "actionNext" E na classe personalizada acima eu adicionei: InputConnection conn = super.onCreateInputConnection (outAttrs); //outAttrs.imeOptions & = ~ EditorInfo.IME_FLAG_NO_ENTER_ACTION; outAttrs.imeOptions & = EditorInfo.IME_ACTION_NEXT; return conn;
yash
Trabalho. Testado em Andorid 6.0.1.
AmiguelS
9

Para fazer isso no Kotlin (e também, opcionalmente, aplicar outras configurações, como textCapSentencesvocê pode usar esta função de extensão:

// To use this, do NOT set inputType on the EditText in the layout
fun EditText.setMultiLineCapSentencesAndDoneAction() {
    imeOptions = EditorInfo.IME_ACTION_DONE
    setRawInputType(InputType.TYPE_TEXT_FLAG_CAP_SENTENCES or InputType.TYPE_TEXT_FLAG_MULTI_LINE)
}

Uso:

myEditText.setMultiLineCapSentencesAndDoneAction()
Ollie C
fonte
1
Funciona a partir de junho de 2019! Obrigado :)
Rohan Taneja
A chave para mim era usar em setRawInputTypevez desetInputType
Tamoxina
9

Acho que é assim que você faz as coisas. Ter android:inputType="textMultiLine", android:imeOptions="actionDone"torna a funcionalidade da chave de entrada ambígua. Apenas tenha em mente que você pode usar android:lines="10"e talvez remover android:inputType="textMultiLine", mas depende do que você deseja alcançar, às vezes você só precisa do android:inputType="textMultiLine"e não há substituto para ele.

EditText ed=new EditText(this);
ed.setOnKeyListener(new OnKeyListener() {
        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {
            if(keyCode == KeyEvent.KEYCODE_ENTER){
                //do your stuff here
            }
            return false;
        }
});
Lukap
fonte
Usar uma quantidade fixa de números máximos com android: lines = "10" funcionou para mim, obtendo o botão ok no teclado. Bom truque se alguém souber quantas linhas haverá, por exemplo, com um pequeno conjunto maxLength.
sunadorer
Eu quero desabilitar o keyCode # 66, é possível? Como eu posso fazer isso?
Adil Malik
1
porque keyCode == 66 em vez de keyCode == EditorInfo.IME_ACTION_GO?
tse
5

Isso parece funcionar perfeitamente para mim

int lineNum = 2;
mEditText.setHorizontallyScrolling(false);
mEditText.setLines(3);
Yonez
fonte
4

Solução Kotlin Reutilizável

Definir esses valores no código foi a única coisa que funcionou para mim

edittext.inputType = EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE
edittext.setHorizontallyScrolling(false)
edittext.maxLines = Integer.MAX_VALUE // Or your preferred fixed value

Eu exijo isso com frequência, então fiz isso para manter o código limpo:

fun EditText.multilineIme(action: Int) {
    imeOptions = action
    inputType = EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE
    setHorizontallyScrolling(false)
    maxLines = Integer.MAX_VALUE
}

// Then just call
edittext.multilineIme(EditorInfo.IME_ACTION_DONE)

Se você deseja adicionar uma ação personalizada opcional em 'Concluído', tente o seguinte:

fun EditText.multilineDone(callback: (() -> Unit)? = null) {
    val action = EditorInfo.IME_ACTION_DONE
    multilineIme(action)
    setOnEditorActionListener { _, actionId, _ ->
            if (action == actionId) {
                callback?.invoke()
                true
            }
            false
        }
    }
}

// Then you can call
edittext.multilineDone { closeKeyboard() }

// or just
edittext.multilineDone()

Precisa controlar facilmente o teclado no retorno de chamada? Leia esta postagem

Em seguida, adicione a hideKeyboard()chamadaEditText.multilineDone

Gibolt
fonte
1
☝️ Esta é uma ótima resposta
Michael,
3

Resposta curta: Não, acredito que não seja possível antes da API de nível 11 (3.0).

O mesmo problema surgiu aqui (discutido nos comentários à resposta aceita):

Botão de ação do teclado Android Soft

Do comentário final:

Olhando para alguns aplicativos no meu telefone, parece comum ter a caixa de várias linhas por último, com um botão "Concluído" ou "Enviar" visível abaixo dela (por exemplo, aplicativo de e-mail).

Martin Stone
fonte
3

Uma maneira simples de contornar essa situação:

  • mantenha estes atributos no EditText:

    android:inputType="textMultiLine" 
    android:scrollHorizontally="false"
  • em seguida, adicione este código para ocultar o teclado apenas quando ENTER for pressionado:

    editText.setOnEditorActionListener(new OnEditorActionListener() 
    {
        public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
        if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) 
        {
            editText.setSelection(0);
            InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);      
            return true;
         } 
         else 
         {
            return false;
         }
         }
    });
Jean Gonçalves
fonte
2

Se não for sobre a aparência do teclado na tela, você poderia simplesmente colocar um ouvinte de entrada no teclado e disparar o status "concluído" se o usuário inserir uma nova linha.

twall
fonte
2

se você usar a opção de entrada textImeMultiline com imeoptions flagnext e actionnext você terá um próximo botão em vez do cariage return

Marcusdev
fonte
2

Embora nenhuma das outras soluções tenha funcionado para mim, as seguintes funcionaram lindamente e me pouparam dias e dias de mais pesquisas no Google, com algumas reviravoltas, é claro. Infelizmente não me lembro de onde obtive o código exatamente e, portanto, não posso dar ao autor o crédito que ele merece.

Em seu código Java:

////////////Code to Hide SoftKeyboard on Enter (DONE) Press///////////////
editText.setRawInputType(InputType.TYPE_CLASS_TEXT|InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD|InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
editText.setImeActionLabel("DONE",EditorInfo.IME_ACTION_DONE);              //Set Return Carriage as "DONE"
editText.setImeOptions(EditorInfo.IME_ACTION_DONE);

editText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
    @Override
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) 
    {
                if (event == null) {
                    if (actionId == EditorInfo.IME_ACTION_DONE) {
                        // Capture soft enters in a singleLine EditText that is the last EditText
                        // This one is useful for the new list case, when there are no existing ListItems
                        editText.clearFocus();
                        InputMethodManager inputMethodManager = (InputMethodManager)  getActivity().getSystemService(Activity.INPUT_METHOD_SERVICE);
                        inputMethodManager.hideSoftInputFromWindow(getActivity().getCurrentFocus().getWindowToken(), 0);
                    }

                    else if (actionId == EditorInfo.IME_ACTION_NEXT) {
                        // Capture soft enters in other singleLine EditTexts
                    } else if (actionId == EditorInfo.IME_ACTION_GO) {
                    } else {
                        // Let the system handle all other null KeyEvents
                        return false;
                    }
                } 
        else if (actionId == EditorInfo.IME_NULL) {
                    // Capture most soft enters in multi-line EditTexts and all hard enters;
                    // They supply a zero actionId and a valid keyEvent rather than
                    // a non-zero actionId and a null event like the previous cases.
                    if (event.getAction() == KeyEvent.ACTION_DOWN) {
                        // We capture the event when the key is first pressed.
                    } else {
                        // We consume the event when the key is released.
                        return true;
                    }
                } 
        else {
                    // We let the system handle it when the listener is triggered by something that
                    // wasn't an enter.
                    return false;
                }
                return true;
        }
});
Kaushik NP
fonte
1

Estou no 4.xe tentei chamar setHorizontallyScrolling () (com ou sem setLine () ou setMaxLines ()), bem como muitas configurações XML diferentes para exibir o botão Concluído. Nenhum deles funcionou. O resultado final é que se o seu EditText for multilinha, o Android sempre desejará mostrar o retorno do carro em vez do botão "Concluído", a menos que você faça algum truque em torno disso.

A solução de menor complicação que encontrei que não envolve o remapeamento do comportamento do retorno de carro está aqui: https://stackoverflow.com/a/12570003/3268329 . Esta solução anulará o desejo implacável do Android de forçar a configuração do sinalizador IME_FLAG_NO_ENTER_ACTION para visualizações multilinhas, o que faz com que o botão Concluído desapareça.

Steve B
fonte
0

Eu também lutei por um bom tempo, mas finalmente encontrei uma solução!

Basta criar uma classe EditText personalizada como:

public class EditTextImeMultiline extends EditText {

    public void init() {
        addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

            }

            @Override
            public void afterTextChanged(Editable s) {
                for (int i = s.length(); i > 0; i--)
                    if (s.subSequence(i - 1, i).toString().equals("\n"))
                        s.replace(i - 1, i, "");
            }
        });
        setSingleLine();
        setHorizontallyScrolling(false);
        this.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                EditTextImeMultiline.this.setLines(EditTextImeMultiline.this.getLineCount());
            }
        });
    }

    public EditTextImeMultiline(Context context) {
        super(context);
        init();
    }

    public EditTextImeMultiline(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public EditTextImeMultiline(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public EditTextImeMultiline(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }
}

Esta classe remove lineBreaks (\ n), quebra o texto como textMultiline faria, E permite que você substitua o botão Enter por um ImeAction;).

Você só precisa chamá-lo em seu XML em vez da classe EditText clássica.

Para explicar a lógica aqui:

  • Defina EditText como uma única linha para poder mostrar um botão ImeAction em vez de Enter.
  • Remova a rolagem horizontal para fazer o texto ir para a próxima linha ao chegar ao final da visualização.
  • Observe as mudanças de layout com o onGlobalLayoutListener e defina o parâmetro "line" para "lineCount" do texto atual mantido pelo editText. Isso é o que atualiza sua altura.
Gabriel Morin
fonte