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ę


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"

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ć.


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" />

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

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

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

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


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


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

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.


2

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


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




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.


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ść.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.