EditText maxLines не работает - пользователь все еще может ввести больше строк, чем установлено

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

Пользователь может ввести более 5 строк, нажав клавишу ввода / следующей строки. Как я могу ограничить ввод пользователя фиксированным количеством строк с помощью EditText?

Индрек Кыуэ
источник
см. этот пост: stackoverflow.com/questions/14672234/…
ali safaei

Ответы:

85

Атрибут maxLinesсоответствует максимальной высоте EditText, он контролирует внешние границы, а не внутренние текстовые строки.

Cedekasme
источник
Я тоже об этом подумал ... Есть ли способ ограничить вводимые строки или мне нужно это программно на бэкэнд-коде?
Индрек Кыуэ
Нет простого способа ограничить вводимые строки, как вы хотите. Вам придется сделать это вручную в своем коде.
Cedekasme
3
Я думаю, что для разработчика "maxLines" подразумевает максимальное количество строк, которое должно быть возможно с помощью editText. Если бы мне просто нужна была определенная высота, я бы использовал «линии». : - /
Someone Somewhere
242
<EditText
    android:id="@+id/edit_text"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:inputType="text"
    android:maxLines="1" 
/>

Вам просто нужно убедиться, что у вас установлен атрибут inputType. Без этой строчки не работает.

android:inputType="text"
Ноэль Чу
источник
3
@Neol Chew Вы правы! Я работал после установки inputTypeна text. Спасибо за то, что сэкономили мое время :-)
by Jevan
6
@byJeevan, я всегда думал, что inputType имеет значение по умолчанию "text". Думаю, я ошибался.
Ноэль Чу
2
Очень странно, что Text не является значением по умолчанию, установленным для inputType, хотя
отличный
9
он работает только для maxLines 1, но вы не можете добавить новую строку
Даниэль Рауф
69

Это не решает общую проблему ограничения n строками. Если вы хотите ограничить свой EditText одной строкой текста, это может быть очень просто.
Вы можете установить это в XML-файле.

android:singleLine="true"

или программно

editText.setSingleLine(true);
Джесси Блэк
источник
8
но что, если вы хотите ограничиться двумя строками? или 3? Для этого вам нужно создать собственный ограничитель строк ...
Индрек Кыуэ
4
Я знаю об этом. «Это не решает общую проблему ограничения n строками». В итоге я прочитал вопрос здесь, пока пытался ограничиться одной строкой и нашел более простое решение. Я подумал, что другие могут в конечном итоге здесь попытаться ограничить свой EditText до 1 строки и реализовать «настраиваемый ограничитель строк». Мой ответ здесь для других пользователей SO, которые в конечном итоге ищут этот вопрос по той же причине, что и я.
Джесси Блэк,
@ IndrekKõue, это не должно быть слишком сложно.
Don Larynx
10
singleLine устарел
Али
1
Атрибут editText singleLine = "true" устарел, и он выйдет из строя на устройствах, использующихся на Android выше 7.0
TranHieu,
24

@Cedekasem, вы правы, встроенного «ограничителя строк» ​​нет. Но я построил его самостоятельно, поэтому, если кому-то интересно, код ниже. Приветствия.

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;
        }
});
Индрек Кыуэ
источник
Это имеет неинтуитивный побочный эффект для пользователя. например, если у вас есть 7 строк в вашем EditText, а затем нажмите Enter в его середине, тогда вы можете попрощаться с последней строкой вашего текста.
miguel.martin 01
не будет работать, если вы вставите в него больше текста, чем maxlines. Так что лучше было бы использовать addTextChangedListener.
Kuldeep Sakhiya
13

Я сделал то, что вы, ребята, искали. Вот мой LimitedEditTextкласс.

Особенности:

  • вы можете ограничить количество строк в вашем компоненте LimitedEditText
  • вы можете ограничить количество символов в вашем компоненте LimitedEditText
  • если вы превысите лимит символов или строк где-то в середине текста, курсор
    не доведет вас до конца - он останется там, где вы были.

Я отключаю слушателя, потому что каждый вызов setText()метода будет рекурсивно вызывать эти 3 метода обратного вызова в случае, когда пользователь превысил лимит символов или строк.

Код:

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

}
bpawlowski
источник
2
Это решение настолько простое и элегантное! Спасибо
GuilhE 03
Использую beforeCursorPosition = getSelectionStart();в afterTextChangedобратном вызове. Он работает лучше , потому что , когда набрав eпосле ввода abcd, то EditText может «думать» заменить abcdс abcde, из - за метода ввода причины.
hanswim
11

Я сделал для этого более простое решение: 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);
        }
    });

Вы можете изменить значение 3 в соответствии txtSpecialRequests.getLineCount() > 3с вашими потребностями.

Оскар Юандината
источник
3
Большое спасибо, наконец-то сработало после нескольких неправильных решений. Это должен быть принятый ответ.
eyadMhanna
Я понимаю, что «txtSpecialRequests» - это ваш контейнер EditText, но где вы устанавливаете переменные lastSpecialRequestsCursorPosition и specialRequests?
мрачная панорама
вне этого метода, конечно :) init lastSpecialRequestsCursorPosition = 0 и specialRequests = ""
Оскар Юандината
Отличное решение!
Маркус
5

Вот InputFilter, который ограничивает допустимые строки в 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;
  }
}

Чтобы добавить его в EditText:

editText.setFilters(new InputFilter[]{new MaxLinesInputFilter(2)});
peceps
источник
Хорошее решение, однако оно решает проблему переноса текста (не вводить)
Peter File
4

Вот что я использовал в своем проекте:

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

И это сработало во всех сценариях

пират
источник
1
В каком контексте нужен TextWatcher? KeyListener был всем, что мне было нужно.
AlanKley
@AlanKley: Нам нужно до и после событий изменения текста, чтобы вычислить количество строк editText. Как будто мы продолжаем вводить текст и не нажимаем клавишу «новая строка», тогда onKey не запускается, и курсор автоматически перемещается на следующую строку. Итак, чтобы отслеживать такие строки, нам нужен textWatcher. Я надеюсь, что смогу вас понять.
Pirate
Понимаю. Спасибо за это разъяснение.
AlanKley
@AlanKley Если вы считаете, что мой ответ полезен, проголосуйте за него.
Пират
public void afterTextChanged (редактируемый arg0) {int lineCount = editText.getLineCount (); если (lineCount> numberOfLines) {editText.setText (текст); }} вызовет исключение StackOverflowException ...
desgraci
4

установить editText android:inputType="text"

Вимал Прабху
источник
3

Самое простое решение:

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());
}
landonmutch
источник
3
android:inputType="text" (or something different to "none")
android:maxLines="1"  (and this line)
Адриан Прието
источник
2

это один подход. Может кому-нибудь помочь.

android:lines="1"
android:maxLines="1"
android:inputType="text
Мохаммед Натар
источник
1

Еще один способ ограничить вас EditTextодной строкой:

editText2.setTransformationMethod(new SingleLineTransformationMethod());

Обратите внимание, что после применения этого метода преобразования клавиша ввода создает пробелы при нажатии. Это все еще отвечает на вопрос TS.

giorgos.nl
источник
Хороший способ скрыть новую строку! Однако в значении все еще будет символ «новой строки» !!
Грегори Штайн
1

Вы можете ограничить свой текст в соответствии с вашим количеством строк, я говорю около 37 алфавитов в одной строке

<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 () - один из вариантов; если вы хотите, чтобы там были ненулевые значения, убедитесь, что ваше представление измерено. Для мягкой клавиатуры onKeyListener не будет работать, поэтому вам нужно добавить addTextChangedListener (), который будет отслеживать изменения текста по мере ввода. Как только вы получите достаточно строк внутри его обратных вызовов, сделайте все, что хотите, чтобы его ограничить: удалите символы с помощью getText (), setText () или что-то более необычное. Вы даже можете ограничить количество символов с помощью фильтра.

Другой вариант - контролировать размер текста с помощью getLineBounds (). Это будет взаимодействовать с гравитацией текста / paddign, так что будьте осторожны.

Влад
источник
0

Для ограничения количества символов мы можем просто использовать свойство maxLength EditText, так как оно не позволит пользователю вводить больше символов.

пират
источник
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

Другая идея: каждый раз после набора новый текст будет сохраняться в String lastText, только если количество строк не превышает MAX_LINES. Если это так, мы бы установили текст EditText на последний добавленный текст (так что изменения будут удалены) и уведомим пользователя, чтобы он оставался коротким.

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

Это продолжение ответа Индрека Кыуэ на Котлин.

                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

Попробуйте использовать следующую комбинацию атрибутов EditText внутри файла xml:

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

ihayet
источник
2
Просто предупреждаю. singleLine устарел. maxLines был введен вместо singleLine.
Sandeep R
@SandeepR Вы ошибаетесь, android:inputTypeзаменяет использованиеandroid:singleLine
Пьер