Многострочный EditText с кнопкой действия Done

114

Можно ли иметь EditTextвиджет с android:inputType="textMultiLine"установленным и android:imeOptions="actionDone"одновременно?

Мне бы хотелось, чтобы многострочное поле редактирования с кнопкой действия на клавиатуре было «Готово», а не «Ввод» (возврат каретки), но похоже, что оно не работает.

заранее спасибо

kefs
источник
А как насчет того, чтобы попробовать составной виджет с комбинированными многострочными EditText и Button?
Субин Себастьян
1
похоже на stackoverflow.com/questions/5014219/…
larham1 06

Ответы:

195

использование

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

и в XML:

android:inputType="textMultiLine"
alexbtr
источник
для меня курсор все еще будет , когда клавиатура пошла вниз, мне нужно , чтобы добавить textField.setCursorVisible(false);внутриonEditorActionListener
Fonix
Работает на 4.2.2 и 7.1.1. Спасибо.
tehcpu 03
1
Работает очень хорошо ... Пытался найти. Этот ответ должен быть отмечен как лучший ответ
MFAL
7
почему это работает, а не настраивает все это в xml?
Эндрю Стейнмец
1
С трудом удалось найти эту информацию. Он по-прежнему работает как шарм!
Костин
51

Из документации Android: ' "textMultiLine" Обычная текстовая клавиатура, которая позволяет пользователям вводить длинные строки текста, которые включают разрывы строк (возврат каретки) . Следовательно, атрибут textMultiLine не подходит, если вы хотите, чтобы на клавиатуре была кнопка «Готово».

Простой способ получить многострочное (в данном случае 3 строки) поле ввода с кнопкой «Готово» - использовать EditText с

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

Однако по какой-то причине это работает для меня, только если я выполняю эти настройки в коде вместо файла макета (в onCreate) с помощью

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

Я надеюсь, что это кому-то поможет, поскольку потребовалось довольно много времени, чтобы понять. Если вы найдете способ заставить его работать из манифеста, сообщите нам об этом.

HYS
источник
4
Я хотел бы также предложить пытается maxLines()вместо того , setLines()если вы хотите , чтобы избежать изменения высотыEditText
Daniel Smith
Я думаю, что в вопросе не уточняется, что вы должны установить android: imeOptions с таким значением, как actionSend. Завершая этот ответ, мне пришлось установить android: singleLine = "true", даже если setMaxLines перезаписывает его по коду (в противном случае вы не получите ключ ввода, например, «Отправить»). Чтобы зафиксировать действие <Enter>, проверьте первый ответ на stackoverflow.com/questions/5014219/… out.
DNax 01
Извините, лучшая альтернатива, которую я нашел для захвата <Enter>, - это ответ @earlcasper здесь stackoverflow.com/questions/1489852/…
DNax
1
Это отлично сработало для меня (используя setMaxLines(3)) Большое спасибо!
лауренцев
1
Работает как шарм: просто добавьте android: imeOptions = "actionDone" android: inputType = "text" в свой XML и удалите android: lines = "3" android: scrollHorizontally = "false" из XML
HannahCarney,
24

Рабочий пример! Создайте указанный ниже настраиваемый класс EditText, который поддерживает эту функцию, и используйте этот класс в файле xml. Рабочий код:

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
источник
Это сработало для меня, мое требование состояло в том, чтобы сделать текст редактирования, который должен быть многострочным, а также иметь следующую кнопку на программных клавишах ............... так что большое спасибо за то, что я сделал был в редактируемом тексте, я добавил 2 строки android: inputType = "textMultiLine" android: imeOptions = "actionNext" И в пользовательском классе выше я сделал: InputConnection conn = super.onCreateInputConnection (outAttrs); //outAttrs.imeOptions & = ~ EditorInfo.IME_FLAG_NO_ENTER_ACTION; outAttrs.imeOptions & = EditorInfo.IME_ACTION_NEXT; return conn;
yash
Работает. Проверено на Andorid 6.0.1.
AmiguelS
9

Чтобы сделать это в Kotlin (а ​​также при желании применить другие конфигурации, например, textCapSentencesвы можете использовать эту функцию расширения:

// 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)
}

Использование:

myEditText.setMultiLineCapSentencesAndDoneAction()
Олли С
источник
1
Работает с июня 2019 года! Спасибо :)
Rohan Taneja
Ключ для меня было использовать setRawInputTypeвместоsetInputType
Tamoxin
9

Я думаю, что это ваш способ поступать так. Наличие android:inputType="textMultiLine", android:imeOptions="actionDone"делает функциональность клавиши ввода неоднозначной. Просто имейте в виду, что вы можете использовать android:lines="10"и, возможно, удалить android:inputType="textMultiLine", но в зависимости от того, чего вы хотите достичь, иногда вам просто нужно, android:inputType="textMultiLine"и ему нет замены.

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
источник
Использование фиксированного количества максимальных чисел с android: lines = "10" помогло мне, получив кнопку ОК на клавиатуре. Хороший трюк, если известно, сколько строк будет, например с небольшим набором maxLength.
sunadorer
Я хочу отключить keyCode # 66, возможно ли это? Как я могу это сделать?
Адиль Малик
1
почему keyCode == 66 вместо keyCode == EditorInfo.IME_ACTION_GO?
tse
5

Кажется, это отлично работает для меня

int lineNum = 2;
mEditText.setHorizontallyScrolling(false);
mEditText.setLines(3);
yonez
источник
4

Многоразовое решение Kotlin

Установка этих значений в коде - единственное, что у меня сработало.

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

Мне это нужно часто, поэтому сделал это, чтобы код был чистым:

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)

Если вы хотите добавить дополнительное настраиваемое действие в «Готово», попробуйте следующее:

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()

Нужно легко управлять клавиатурой в обратном вызове? Прочтите этот пост

Затем добавьте hideKeyboard()звонокEditText.multilineDone

Gibolt
источник
1
☝️Это отличный ответ
Майкл
3

Краткий ответ: нет, я считаю, что это невозможно до уровня API 11 (3.0).

Здесь возникла та же проблема (обсуждается в комментариях к принятому ответу):

Кнопка действия мягкой клавиатуры Android

Из последнего комментария:

Глядя на несколько приложений на моем телефоне, кажется обычным, что многострочное поле находится последним с видимой кнопкой «Готово» или «Отправить» под ним (например, приложение электронной почты).

Мартин Стоун
источник
3

Простой способ обойти эту ситуацию:

  • сохраните эти атрибуты в EditText:

    android:inputType="textMultiLine" 
    android:scrollHorizontally="false"
  • затем добавьте этот код, чтобы скрыть клавиатуру только при нажатии ENTER:

    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;
         }
         }
    });
Жан Гонсалвес
источник
2

Если дело не во внешнем виде экранной клавиатуры, вы можете просто поместить прослушиватель ввода на клавиатуру и активировать статус «готово», если пользователь вводит новую строку.

twall
источник
2

если вы используете параметр ввода textImeMultiline с imeoptions flagnext и actionnext, вы получите следующую кнопку вместо возврата cariage

Marcusdev
источник
2

Хотя ни одно из других решений никогда не помогало мне, сработало следующее прекрасно и сэкономило мне дни и дни, когда нужно было больше гуглить, с некоторыми собственными поворотами, конечно. К сожалению, я не помню, откуда я взял код, и поэтому не могу отдать должное автору, которого он / она заслуживает.

В вашем 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;
        }
});
Кошик Н.П.
источник
Вероятно, из gist.github.com/Dogesmith/2b98df97b4fca849ff94
Наз
Вероятно, из gist.github.com/Dogesmith/2b98df97b4fca849ff94
Наз
Вероятно, из gist.github.com/Dogesmith/2b98df97b4fca849ff94
Наз
1

Я использую 4.x и пробовал вызвать setHorizontallyScrolling () (с setLine () или setMaxLines () или без них), а также множество различных конфигураций XML, чтобы отобразить кнопку Done. Ни один из них не работал. Суть в том, что если ваш EditText является многострочным, Android всегда захочет показывать возврат каретки вместо кнопки «Готово», если только вы не добавите какие-то хаки для этого.

Решение с наименьшей сложностью, которое я обнаружил, которое не включает переназначение поведения возврата каретки, находится здесь: https://stackoverflow.com/a/12570003/3268329 . Это решение сведет на нет неустанное желание Android принудительно установить флаг IME_FLAG_NO_ENTER_ACTION для многострочных представлений, из-за чего кнопка «Готово» исчезнет.

Стив Б.
источник
0

Я тоже довольно долго боролся, но наконец нашел решение!

Просто создайте собственный класс EditText как таковой:

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();
    }
}

Этот класс удаляет lineBreaks (\ n), обертывает текст, как это сделал бы textMultiline, И позволяет вам заменить кнопку Enter на ImeAction;).

Вам просто нужно вызвать его в своем XML вместо классического класса EditText.

Чтобы объяснить логику здесь:

  • Установите EditText как singleLine, чтобы можно было отображать кнопку ImeAction вместо Enter.
  • Удалите горизонтальную прокрутку, чтобы текст переходил на следующую строку при достижении конца представления.
  • Наблюдайте за изменениями макета с помощью onGlobalLayoutListener и установите для его параметра «line» значение «lineCount» текущего текста, содержащегося в editText. Это то, что освежает его высоту.
Габриэль Морин
источник