EditText maxLines nie działa - użytkownik wciąż może wprowadzić więcej wierszy niż ustawione


127
<EditText 
    android:id="@+id/editText2" 
    android:layout_height="wrap_content" 
    android:layout_width="fill_parent" 
    android:maxLines="5" 
    android:lines="5">
</EditText>

Użytkownik może wprowadzić więcej niż 5 wierszy, naciskając klawisz Enter / następny wiersz. Jak mogę ograniczyć dane wejściowe użytkownika do stałej liczby wierszy za pomocą EditText?


Odpowiedzi:


85

Atrybut maxLinesodpowiada maksymalnej wysokości EditText, kontroluje zewnętrzne granice, a nie wewnętrzne linie tekstu.


Tak też pomyślałem ... Czy istnieje sposób na ograniczenie wprowadzanych wierszy, czy też muszę programowo to robić w kodzie zaplecza?
Indrek Kõue,

Nie ma prostego sposobu na ograniczenie wprowadzanych linii, tak jak chcesz. Będziesz musiał to zrobić ręcznie w swoim kodzie.
Cedekasme

3
Myślę, że dla programisty "maxLines" oznacza maksymalną liczbę wierszy, które powinny być możliwe z editText. Gdybym chciał mieć określoną wysokość, użyłbym „linii”. : - /
Someone Somewhere

241
<EditText
    android:id="@+id/edit_text"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:inputType="text"
    android:maxLines="1" 
/>

Musisz tylko upewnić się, że masz ustawiony atrybut „inputType”. Nie działa bez tej linii.

android:inputType="text"

3
@Neol Chew Masz rację! Pracowałem po ustawieniu inputTypesię text. Dzięki za zaoszczędzenie czasu :-)
autorJeevan,

6
@byJeevan, zawsze myślałem, że inputType ma domyślną wartość „text”. Chyba się myliłem.
Noel Chew

2
Bardzo dziwne, że Text nie jest domyślną wartością ustawioną dla inputType, chociaż świetna odpowiedź
Muhammed Refaat

9
działa tylko dla maxLines o wartości 1, ale nie możesz dodać nowej linii
Daniel Raouf

69

Nie rozwiązuje to ogólnego problemu ograniczenia do n linii. Jeśli chcesz ograniczyć swój EditText do jednej linii tekstu, może to być bardzo proste.
Możesz to ustawić w pliku xml.

android:singleLine="true"

lub programowo

editText.setSingleLine(true);

8
ale co jeśli chcesz ograniczyć do 2 rzędów? czy 3? W tym celu musisz zbudować niestandardowy ogranicznik wierszy ...
Indrek Kõue

4
Jestem tego świadomy. „Nie rozwiązuje to ogólnego problemu ograniczenia do n linii”. Skończyło się na tym, że przeczytałem tutaj pytanie, próbując ograniczyć do jednej linii i znalazłem łatwiejsze rozwiązanie. Pomyślałem, że inni mogą skończyć tutaj, chcąc ograniczyć swój tekst EditText do 1 linii i zaimplementować „niestandardowy ogranicznik wierszy”. Moja odpowiedź jest tutaj dla innych użytkowników SO, którzy w końcu wyszukują to pytanie z tego samego powodu co ja.
Jesse Black

@ IndrekKõue to nie powinno być zbyt trudne.
Don Larynx

10
singleLine jest przestarzałe
Ali

1
Atrybut editText singleLine = "true" jest przestarzały i nastąpi awaria na urządzeniach z systemem Android w wersji
wyższej

24

@Cedekasem masz rację, nie ma wbudowanego "ogranicznika wierszy". Ale zbudowałem samodzielnie, więc jeśli ktoś jest zainteresowany, kod znajduje się poniżej. Twoje zdrowie.

et.setOnKeyListener(new View.OnKeyListener() {

        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {

            // if enter is pressed start calculating
            if (keyCode == KeyEvent.KEYCODE_ENTER
                    && event.getAction() == KeyEvent.ACTION_UP) {

                // get EditText text
                String text = ((EditText) v).getText().toString();

                // find how many rows it cointains
                int editTextRowCount = text.split("\\n").length;

                // user has input more than limited - lets do something
                // about that
                if (editTextRowCount >= 7) {

                    // find the last break
                    int lastBreakIndex = text.lastIndexOf("\n");

                    // compose new text
                    String newText = text.substring(0, lastBreakIndex);

                    // add new text - delete old one and append new one
                    // (append because I want the cursor to be at the end)
                    ((EditText) v).setText("");
                    ((EditText) v).append(newText);

                }
            }

            return false;
        }
});

Ma to nieintuicyjny efekt uboczny dla użytkownika. np. jeśli masz 7 wierszy w swoim EditText, a następnie naciśniesz Enter w środku, możesz powiedzieć „żegnaj” do ostatniej linii tekstu.
miguel.martin

nie zadziała, jeśli wkleisz do niego więcej niż maxlines tekstu. Więc lepiej byłoby użyć addTextChangedListener.
Kuldeep Sakhiya

13

Zrobiłem coś, czego szukaliście. Oto moja LimitedEditTextklasa.

Cechy:

  • możesz ograniczyć liczbę wierszy w komponencie LimitedEditText
  • możesz ograniczyć liczbę znaków w komponencie LimitedEditText
  • jeśli przekroczysz limit znaków lub linii gdzieś w środku tekstu, kursor
    nie przeniesie Cię do końca - pozostanie tam, gdzie byłeś.

Wyłączam nasłuchiwanie, ponieważ każde wywołanie setText()metody wywoływałoby rekurencyjnie te 3 metody wywołania zwrotnego w przypadku, gdy użytkownik przekroczył limit znaków lub linii.

Kod:

import android.content.Context;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.EditText;
import android.widget.Toast;

/**
* EditText subclass created to enforce limit of the lines number in editable
* text field
*/
public class LimitedEditText extends EditText {

/**
 * Max lines to be present in editable text field
 */
private int maxLines = 1;

/**
 * Max characters to be present in editable text field
 */
private int maxCharacters = 50;

/**
 * application context;
 */
private Context context;

public int getMaxCharacters() {
    return maxCharacters;
}

public void setMaxCharacters(int maxCharacters) {
    this.maxCharacters = maxCharacters;
}

@Override
public int getMaxLines() {
    return maxLines;
}

@Override
public void setMaxLines(int maxLines) {
    this.maxLines = maxLines;
}

public LimitedEditText(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    this.context = context;
}

public LimitedEditText(Context context, AttributeSet attrs) {
    super(context, attrs);
    this.context = context;
}

public LimitedEditText(Context context) {
    super(context);
    this.context = context;
}

@Override
protected void onFinishInflate() {
    super.onFinishInflate();

    TextWatcher watcher = new TextWatcher() {

        private String text;
        private int beforeCursorPosition = 0;

        @Override
        public void onTextChanged(CharSequence s, int start, int before,
                int count) {                
            //TODO sth
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count,
                int after) {
            text = s.toString();
            beforeCursorPosition = start;
        }

        @Override
        public void afterTextChanged(Editable s) {

            /* turning off listener */
            removeTextChangedListener(this);

            /* handling lines limit exceed */
            if (LimitedEditText.this.getLineCount() > maxLines) {
                LimitedEditText.this.setText(text);
                LimitedEditText.this.setSelection(beforeCursorPosition);
            }

            /* handling character limit exceed */
            if (s.toString().length() > maxCharacters) {
                LimitedEditText.this.setText(text);
                LimitedEditText.this.setSelection(beforeCursorPosition);
                Toast.makeText(context, "text too long", Toast.LENGTH_SHORT)
                        .show();
            }

            /* turning on listener */
            addTextChangedListener(this);

        }
    };

    this.addTextChangedListener(watcher);
}

}

2
To takie proste i eleganckie rozwiązanie! Dzięki
GuilhE

Używam beforeCursorPosition = getSelectionStart();w afterTextChangedoddzwonieniu. Działa lepiej, ponieważ podczas pisania epo wpisaniu abcd, EditText może „pomyśleć”, że go zastąpisz, abcdz abcdepowodu metody wprowadzania.
hanswim

11

Zrobiłem dla tego prostsze rozwiązanie: D

// set listeners
    txtSpecialRequests.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            lastSpecialRequestsCursorPosition = txtSpecialRequests.getSelectionStart();
        }

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

        }

        @Override
        public void afterTextChanged(Editable s) {
            txtSpecialRequests.removeTextChangedListener(this);

            if (txtSpecialRequests.getLineCount() > 3) {
                txtSpecialRequests.setText(specialRequests);
                txtSpecialRequests.setSelection(lastSpecialRequestsCursorPosition);
            }
            else
                specialRequests = txtSpecialRequests.getText().toString();

            txtSpecialRequests.addTextChangedListener(this);
        }
    });

Możesz zmienić wartość 3 cali txtSpecialRequests.getLineCount() > 3według swoich potrzeb.


3
Dziękuję bardzo, w końcu zadziałałem po wielu błędnych rozwiązaniach. To powinna być akceptowana odpowiedź.
eyadMhanna

Rozumiem, że „txtSpecialRequests” to Twój kontener EditText, ale gdzie ustawiasz zmienne lastSpecialRequestsCursorPosition i specialRequests?
ponury panoramiczny

oczywiście poza tą metodą :) init lastSpecialRequestsCursorPosition = 0 i specialRequests = ""
Oscar Yuandinata

Świetne rozwiązanie!
Marcus

5

Oto InputFilter, który ogranicza dozwolone linie w EditText:

/**
 * Filter for controlling maximum new lines in EditText.
 */
public class MaxLinesInputFilter implements InputFilter {

  private final int mMax;

  public MaxLinesInputFilter(int max) {
    mMax = max;
  }

  public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
    int newLinesToBeAdded = countOccurrences(source.toString(), '\n');
    int newLinesBefore = countOccurrences(dest.toString(), '\n');
    if (newLinesBefore >= mMax - 1 && newLinesToBeAdded > 0) {
      // filter
      return "";
    }

    // do nothing
    return null;
  }

  /**
   * @return the maximum lines enforced by this input filter
   */
  public int getMax() {
    return mMax;
  }

  /**
   * Counts the number occurrences of the given char.
   *
   * @param string the string
   * @param charAppearance the char
   * @return number of occurrences of the char
   */
  public static int countOccurrences(String string, char charAppearance) {
    int count = 0;
    for (int i = 0; i < string.length(); i++) {
      if (string.charAt(i) == charAppearance) {
        count++;
      }
    }
    return count;
  }
}

Aby dodać go do EditText:

editText.setFilters(new InputFilter[]{new MaxLinesInputFilter(2)});

Dobre rozwiązanie, jednak rozwiązuje problem zawijania tekstu (nie wpisuj)
Peter File

4

Oto, czego użyłem w moim projekcie:

editText.addTextChangedListener(new TextWatcher() {
    private String text;

public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {    
}

public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
    text = arg0.toString();
    }

public void afterTextChanged(Editable arg0) {
    int lineCount = editText.getLineCount();
    if(lineCount > numberOfLines){
    editText.setText(text);
    }
}
});

editText.setOnKeyListener(new View.OnKeyListener() {

public boolean onKey(View v, int keyCode, KeyEvent event) {

// if enter is pressed start calculating
    if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_DOWN){    
    int editTextLineCount = ((EditText)v).getLineCount();
    if (editTextLineCount >= numberOfLines)
        return true;
}

return false;
}
});

I działało we wszystkich scenariuszach


1
W jakim kontekście jest potrzebny TextWatcher? KeyListener był wszystkim, czego potrzebowałem.
AlanKley

@AlanKley: Potrzebujemy przed i po zmianie tekstu, aby obliczyć liczbę wierszy editText. Tak jakbyśmy kontynuowali wprowadzanie tekstu i nie wciskali klawisza "nowa linia", to onKey nie odpala, a kursor automatycznie przenosi się do następnej linii. Więc do śledzenia tego rodzaju linii potrzebujemy textWatcher. Mam nadzieję, że uda mi się Cię zrozumieć.
Pirate

Widzę. Dzięki za wyjaśnienie.
AlanKley

@AlanKley Jeśli uważasz, że moja odpowiedź jest przydatna, zagłosuj na nią.
Pirate

public void afterTextChanged (Editable arg0) {int lineCount = editText.getLineCount (); if (lineCount> numberOfLines) {editText.setText (tekst); }} wyrzuci
wyjątek


3

Najprostsze rozwiązanie:

android:maxLines="3"

...

 @Override
public void afterTextChanged(Editable editable) {
    // limit to 3 lines
    if (editText.getLayout().getLineCount() > 3)
        editText.getText().delete(editText.getText().length() - 1, editText.getText().length());
}

3
android:inputType="text" (or something different to "none")
android:maxLines="1"  (and this line)

2

to jest jedno podejście. Może komuś pomóc.

android:lines="1"
android:maxLines="1"
android:inputType="text

1

Innym sposobem ograniczenia EditTextdo jednej linii jest:

editText2.setTransformationMethod(new SingleLineTransformationMethod());

Zwróć uwagę, że po zastosowaniu tej metody transformacji klawisz Enter tworzy spacje po naciśnięciu. To nadal spełnia pytanie TS.


Niezły sposób na ukrycie nowej linii! Jednak w wartości nadal będzie znak „nowej linii” !!
Gregory Stein

1

Możesz ograniczyć swój tekst do liczby linii, mówię około 37 alfabetów w jednej linii

<EditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:lines="4"
    android:maxLines="4"
    android:minLines="4"
    android:maxLength="150"
    android:gravity="start"
    android:background="#efeef5"
    android:layout_marginTop="@dimen/pad_10dp"/>

0

getLineCount () jest jedną z opcji; jeśli chcesz mieć wartości niezerowe, upewnij się, że Twój widok jest mierzony. W przypadku klawiatury programowej onKeyListener nie działa, więc musisz dodać addTextChangedListener (), który będzie śledzić zmiany tekstu podczas pisania. Jak tylko uzyskasz wystarczającą liczbę wierszy w jego wywołaniach zwrotnych, zrób wszystko, co chcesz, aby je ograniczyć: usuń znaki za pomocą getText (), setText () lub czegoś bardziej wyszukanego. Możesz nawet ograniczyć liczbę znaków za pomocą filtra.

Inną opcją jest monitorowanie rozmiaru tekstu za pomocą metody getLineBounds (). Będzie to oddziaływać z grawitacją / paddign tekstu, więc bądź ostrożny.


0

Aby ograniczyć liczbę znaków, możemy po prostu użyć właściwości maxLength elementu EditText, ponieważ nie pozwoli to użytkownikowi na wprowadzenie większej liczby znaków.


0
        <EditText
            android:id="@+id/usrusr"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:gravity="center"
            android:lines="1"
            android:maxLines="1"
            android:inputType="text"
            android:hint="@string/inventory_no" />

0

Inny pomysł: za każdym razem po wpisaniu, nowy tekst byłby zapisywany jako String lastText, tylko jeśli liczba linii nie przekracza MAX_LINES. Jeśli tak, ustawilibyśmy tekst EditText na ostatnio dodany tekst (aby zmiany zostały usunięte) i powiadomilibyśmy użytkownika, aby był krótki.

 // Set listener to wishDescriptionEditText in order to limit line number
    editText.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) {
            // If line account is higher than MAX_LINES, set text to lastText
            // and notify user (by Toast)
            if (editText.getLineCount() > MAX_LINES) {
                editText.setText(lastText);
                Toast.makeText(getContext(), "Please keep it short", Toast.LENGTH_LONG).show();
            } else {
                lastText = editText.getText().toString();
            }
        }
    });

0

To jest rozszerzenie odpowiedzi Indreka Kõue na temat Kotlina

                input_name.addTextChangedListener(object : TextWatcher {
                override fun afterTextChanged(s: Editable?) {}

                override fun beforeTextChanged(
                    s: CharSequence?,
                    start: Int,
                    count: Int,
                    after: Int
                ) {
                }

                @SuppressLint("SetTextI18n")
                override fun onTextChanged(
                    s: CharSequence?,
                    start: Int,
                    before: Int,
                    count: Int
                ) {
                    val text = (input_name as EditText).text.toString()
                    val editTextRowCount = input_name.lineCount
                    if (editTextRowCount > 15) {
                        val newText = text.substring(0, text.length - 1)
                        input_name.setText("")
                        input_name.append(newText)
                    }
                }
            })

-4

Spróbuj użyć następującej kombinacji atrybutów EditText w pliku xml:

android:singleLine="true"
android:maxLength="22"


2
Tylko jedno ostrzeżenie. singleLine jest przestarzała. maxLines zostało wprowadzone w miejsce singleLine.
Sandeep R

@SandeepR Mylisz się, android:inputTypezastępuje użycieandroid:singleLine
Pierre
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.