Wielowierszowy tekst edycji z przyciskiem czynności Gotowe

114

Czy można mieć EditTextwidżet z android:inputType="textMultiLine"zestawem, a android:imeOptions="actionDone"jednocześnie?

Chciałbym mieć wielowierszowe pole edycji z przyciskiem akcji na klawiaturze do wykonania, a nie Enter (powrót karetki), ale wygląda na to, że nie działa.

Z góry dziękuję

kefs
źródło
A co z wypróbowaniem widgetu złożonego z połączonymi razem wielowierszowym EditText i Button?
Subin Sebastian

Odpowiedzi:

195

Posługiwać się

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

iw XML:

android:inputType="textMultiLine"
alexbtr
źródło
dla mnie kursor nadal pokazywałby się, gdy klawiatura opadła, musiałem dodać textField.setCursorVisible(false);wewnątrzonEditorActionListener
Fonix
Działa na 4.2.2 i 7.1.1. Dzięki.
tehcpu
1
Działa bardzo dobrze ... Próbowałem go znaleźć. Ta odpowiedź powinna być oznaczona jako najlepsza odpowiedź
MFAL
7
dlaczego to działa w przeciwieństwie do konfigurowania wszystkiego w XML?
Andrew Steinmetz,
1
Trudno było znaleźć te informacje. Nadal działa jak urok!
Costin
51

Z dokumentacji systemu Android: ' "textMultiLine" Normalna klawiatura tekstowa, która umożliwia użytkownikom wprowadzanie długich ciągów tekstu zawierających znaki końca wiersza (powrót karetki) . Dlatego atrybut textMultiLine nie jest odpowiedni, jeśli chcesz mieć przycisk „Gotowe” na klawiaturze.

Prostym sposobem uzyskania wielowierszowego (w tym przypadku 3 wierszy) pola wejściowego za pomocą przycisku Gotowe jest użycie EditText z

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

Jednak z jakiegoś powodu działa to tylko wtedy, gdy dokonam tych ustawień w kodzie zamiast w pliku układu (w onCreate) przez

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

Mam nadzieję, że to komuś pomoże, ponieważ ustalenie tego zajęło trochę czasu. Jeśli znajdziesz sposób, aby to zadziałało z manifestu, daj nam znać.

HYS
źródło
4
Sugerowałbym również spróbować maxLines()zamiast, setLines()jeśli chcesz uniknąć zmiany wysokościEditText
Daniel Smith
Myślę, że w pytaniu nie sprecyzowano, że należy ustawić android: imeOptions z wartością taką jak actionSend. Uzupełniając tę ​​odpowiedź, musiałem ustawić android: singleLine = "true", nawet jeśli setMaxLines w pewnym sensie nadpisuje go kodem (nie zrobienie tego nie da ci klawisza enter z np. "Wyślij"). Aby uchwycić akcję <Enter>, sprawdź pierwszą odpowiedź ze stackoverflow.com/questions/5014219/… out.
DNax
Przykro mi, najlepszą alternatywą dotyczącą przechwytywania <Enter>, jaką znalazłem, jest @earlcasper, odpowiedź tutaj stackoverflow.com/questions/1489852/ ...
DNax
1
To zadziałało idealnie dla mnie (używając setMaxLines(3)) Wielkie dzięki!
laurencevs
1
Działało jak marzenie: po prostu dodaj android: imeOptions = "actionDone" android: inputType = "text" również do swojego XML i usuń android: lines = "3" android: scrollHorizontally = "false" z XML
HannahCarney
24

Przykład roboczy! Utwórz poniższą niestandardową klasę EditText, która obsługuje tę funkcję i użyj tej klasy w pliku xml. Kod roboczy:

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
źródło
To zadziałało dla mnie moim wymaganiem było utworzenie tekstu edycji, który powinien być wieloliniowy, a także powinien mieć następny przycisk na klawiszach programowych ............... więc wielkie dzięki za to, co zrobiłem był w tekście edycji dodałem 2 linie android: inputType = "textMultiLine" android: imeOptions = "actionNext" A w klasie niestandardowej powyżej zrobiłem: InputConnection conn = super.onCreateInputConnection (outAttrs); //outAttrs.imeOptions & = ~ EditorInfo.IME_FLAG_NO_ENTER_ACTION; outAttrs.imeOptions & = EditorInfo.IME_ACTION_NEXT; return conn;
yash
Pracuje. Testowany na Andorid 6.0.1.
AmiguelS
9

Aby to zrobić w Kotlin (a także opcjonalnie zastosuj inne konfiguracje, takie jak textCapSentencesmożesz użyć tej funkcji rozszerzenia:

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

Stosowanie:

myEditText.setMultiLineCapSentencesAndDoneAction()
Ollie C
źródło
1
Działa od czerwca 2019! Dzięki :)
Rohan Taneja
Kluczem dla mnie było użycie setRawInputTypezamiastsetInputType
Tamoxin
9

Myślę, że to jest sposób na zrobienie tego. Posiadanie sprawia android:inputType="textMultiLine", android:imeOptions="actionDone"że funkcjonalność klawisza enter jest niejednoznaczna. Pamiętaj tylko, że możesz użyć android:lines="10"i być może usunąć android:inputType="textMultiLine", ale zależy to od tego, co chcesz osiągnąć, czasami po prostu potrzebujesz android:inputType="textMultiLine"i nie ma dla niego zamiennika.

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
źródło
Użycie ustalonej liczby maksymalnych liczb w Androidzie: lines = "10" zadziałało, uzyskując przycisk OK na klawiaturze. Dobra sztuczka, jeśli wiadomo, ile będzie tam linii, na przykład przy małym ustawieniu maxLength.
sunadorer
Chcę wyłączyć keyCode # 66, czy to możliwe? Jak mogę to zrobić?
Adil Malik,
1
dlaczego keyCode == 66 zamiast keyCode == EditorInfo.IME_ACTION_GO?
tse
5

Wydaje mi się, że to działa doskonale

int lineNum = 2;
mEditText.setHorizontallyScrolling(false);
mEditText.setLines(3);
yonez
źródło
4

Wielokrotnego użytku rozwiązanie Kotlin

Ustawienie tych wartości w kodzie było jedyną rzeczą, która działała dla mnie

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

Często tego potrzebuję, więc zrobiłem to, aby kod był czysty:

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)

Jeśli chcesz dodać opcjonalne działanie niestandardowe do „Gotowe”, spróbuj tego:

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

Chcesz łatwo sterować klawiaturą podczas oddzwaniania? Przeczytaj ten post

Następnie dodaj hideKeyboard()połączenieEditText.multilineDone

Gibolt
źródło
1
☝️ To świetna odpowiedź
Michael
3

Krótka odpowiedź: nie, uważam, że nie jest to możliwe przed API na poziomie 11 (3.0).

Ten sam problem pojawił się tutaj (omawiany w komentarzach do zaakceptowanej odpowiedzi):

Przycisk akcji klawiatury Android Soft

Od ostatniego komentarza:

Patrząc na kilka aplikacji na moim telefonie, wydaje się, że pole wielowierszowe jest często umieszczane na końcu, z widocznym przyciskiem „Gotowe” lub „Wyślij” pod nim (np. Aplikacja e-mail).

Martin Stone
źródło
3

Prosty sposób na obejście tej sytuacji:

  • zachowaj te atrybuty w EditText:

    android:inputType="textMultiLine" 
    android:scrollHorizontally="false"
  • następnie dodaj ten kod, aby ukryć klawiaturę tylko po naciśnięciu klawisza 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;
         }
         }
    });
Jean Gonçalves
źródło
2

Jeśli nie chodzi o wygląd klawiatury ekranowej, możesz po prostu umieścić na klawiaturze odbiornik wejścia i uruchomić stan „gotowe”, jeśli użytkownik wprowadzi znak nowej linii.

twall
źródło
2

jeśli użyjesz opcji tekstowej textImeMultiline z opcją imeoptions flagnext i actionnext, otrzymasz następny przycisk zamiast powrotu kariagu

Marcusdev
źródło
2

Podczas gdy żadne z innych rozwiązań nigdy dla mnie nie działało, poniższe działały pięknie i zaoszczędziły mi dni i dni więcej googlowania, oczywiście z kilkoma własnymi zwrotami akcji. Niestety nie pamiętam, skąd dokładnie otrzymałem kod, więc nie mogę przyznać autorowi kredytu, na który zasługuje.

W Twoim kodzie 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
źródło
1

Jestem na 4.x i próbowałem wywołać setHorizontallyScrolling () (z lub bez setLine () lub setMaxLines ()), a także wiele różnych konfiguracji XML, aby wyświetlić przycisk Gotowe. Żaden z nich nie działał. Najważniejsze jest to, że jeśli Twój EditText jest wielowierszowy, Android zawsze będzie chciał pokazać powrót karetki zamiast przycisku „Gotowe”, chyba że dodasz trochę hackowania.

Najmniej skomplikowane rozwiązanie, które znalazłem, które nie wymaga ponownego odwzorowania zachowania powrotu karetki, jest tutaj: https://stackoverflow.com/a/12570003/3268329 . To rozwiązanie zniweczy nieustającą chęć Androida do wymuszenia ustawienia flagi IME_FLAG_NO_ENTER_ACTION dla widoków wieloliniowych, co powoduje zniknięcie przycisku Gotowe.

Steve B.
źródło
0

Przez jakiś czas też walczyłem, ale w końcu znalazłem rozwiązanie!

Po prostu utwórz własną klasę EditText jako taką:

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

Ta klasa usuwa lineBreaks (\ n), zawija tekst tak, jak zrobiłoby to textMultiline, ORAZ pozwala zastąpić przycisk Enter przez ImeAction;).

Wystarczy wywołać to w swoim XML zamiast klasycznej klasy EditText.

Aby wyjaśnić logikę tutaj:

  • Ustaw EditText jako singleLine, aby móc wyświetlać przycisk ImeAction zamiast Enter.
  • Usuń przewijanie w poziomie, aby tekst przeszedł do następnego wiersza po osiągnięciu końca widoku.
  • Obserwuj zmiany układu za pomocą onGlobalLayoutListener i ustaw jego parametr „line” na „lineCount” bieżącego tekstu przechowywanego przez editText. To odświeża jego wysokość.
Gabriel Morin
źródło