O EditText maxLines não está funcionando - o usuário ainda pode inserir mais linhas do que o definido

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

O usuário pode inserir mais de 5 linhas pressionando a tecla Enter / próxima linha. Como posso limitar a entrada do usuário para uma quantidade fixa de linhas com o EditText?

Indrek Kõue
fonte
Veja esta publicação: stackoverflow.com/questions/14672234/…
ali safaei

Respostas:

84

O atributo maxLinescorresponde à altura máxima do EditText, controla os limites externos e não as linhas de texto internas.

Cedekasme
fonte
Foi o que eu pensei também ... Existe uma maneira de limitar as linhas inseridas ou eu tenho isso no código de back-end programaticamente?
Indrek Kõue
Não há uma maneira simples de limitar as linhas inseridas como você deseja. Você precisará fazer isso manualmente no seu código.
Cedekasme
3
Eu acho que para um desenvolvedor "maxLines" implica o número máximo de linhas que deveriam ser possíveis com um editText. Se eu apenas quisesse uma altura específica, usaria "linhas". : - /
Alguém em algum lugar
241
<EditText
    android:id="@+id/edit_text"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:inputType="text"
    android:maxLines="1" 
/>

Você só precisa ter o atributo "inputType" definido. Não funciona sem essa linha.

android:inputType="text"
Noel Chew
fonte
3
@ Neol Chew Você está certo! Eu trabalhei depois de definir inputTypepara text. Obrigado por poupar o meu tempo :-)
porJeevan
6
@byJeevan, eu sempre pensei que inputType tem um valor padrão de "texto". Acho que eu estava errado.
precisa saber é o seguinte
2
Muito estranho que o texto não seja o valor padrão definido para inputType, ótima resposta embora
Muhammed Refaat
9
ele funciona para maxLines de apenas 1, mas você não pode adicionar nova linha
Daniel Raouf
68

Isso não resolve a questão geral de limitar n linhas. Se você deseja limitar seu EditText para receber apenas 1 linha de texto, isso pode ser muito fácil.
Você pode definir isso no arquivo xml.

android:singleLine="true"

ou programaticamente

editText.setSingleLine(true);
Jesse Black
fonte
8
mas e se você quiser limitar a 2 linhas? ou 3? Por que você tem que limitador de construção fileira costume ...
Indrek Koue
4
Estou ciente disso. "Isso não resolve a questão geral de limitar n linhas". Acabei lendo a pergunta aqui enquanto tentava limitar a 1 linha e encontrei uma solução mais fácil. Imaginei que outras pessoas poderiam acabar aqui procurando limitar o EditText para 1 linha e implementar o "limitador de linha personalizado". Minha resposta está aqui para outros usuários de SO que acabam pesquisando essa pergunta pelo mesmo motivo que eu fiz.
Jesse Preto
@ IndrekKõue que não deve ser muito difícil.
Don Larynx
10
singleLine está obsoleto
Ali
1
atributo de EditText singleLine = "true" é obsoleto e Vai falhar em dispositivos estão usando a Android maior do que 7,0
TranHieu
24

@Cedekasem você está certo, não existe um "limitador de linha" embutido. Mas eu construí um eu mesmo, então se alguém estiver interessado, o código está abaixo. Felicidades.

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;
        }
});
Indrek Kõue
fonte
Isso tem um efeito colateral pouco intuitivo para o usuário. por exemplo, se você tiver 7 linhas no seu EditText e, em seguida, pressione enter no meio, poderá dizer adeus à última linha do seu texto.
Miguel.martin
não funcionará se você colar mais do que o máximo de linhas de texto nele. Tão melhor seria usar addTextChangedListener.
Kuldeep Sakhiya 31/03
13

Eu fiz algo como vocês estavam procurando. Aqui está a minha LimitedEditTextaula.

Recursos:

  • você pode limitar a contagem de linhas no seu componente LimitedEditText
  • você pode limitar a contagem de caracteres no seu componente LimitedEditText
  • se você exceder o limite de caracteres ou linhas em algum lugar no meio do texto, o cursor
    não o levará ao fim - ele permanecerá onde esteve.

Estou desativando o ouvinte, porque cada chamada de setText()método chama recursivamente esses três métodos de retorno de chamada no caso em que o usuário excede o limite de caracteres ou linhas.

Código:

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
fonte
2
Esta solução é tão simples e elegante! Obrigado
GuilhE
Eu uso beforeCursorPosition = getSelectionStart();em afterTextChangedretorno de chamada. Funciona melhor porque, ao digitar eapós digitar abcd, o EditText pode 'pensar' que você substitui abcdpor abcdecausa do motivo do método de entrada.
hanswim
11

Eu fiz a solução mais simples para isso: 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);
        }
    });

Você pode alterar o valor de 3 polegadas txtSpecialRequests.getLineCount() > 3para suas necessidades.

Oscar Yuandinata
fonte
3
Muito obrigado, finalmente funcionou após várias soluções erradas. Essa deve ser a resposta aceita.
precisa saber é o seguinte
Eu entendo que "txtSpecialRequests" é seu contêiner EditText, mas onde você define as variáveis ​​lastSpecialRequestsCursorPosition e specialRequests?
drearypanoramic
fora deste método, é claro :) init lastSpecialRequestsCursorPosition = 0 e specialRequests = ""
Oscar Yuandinata
Ótima solução!
Marcus
5

Aqui está um InputFilter que limita as linhas permitidas no 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;
  }
}

Para adicioná-lo ao EditText:

editText.setFilters(new InputFilter[]{new MaxLinesInputFilter(2)});
peceps
fonte
Boa solução, no entanto, ele faz endereço a questão da quebra de texto (não entra)
Peter Arquivo
4

Isto é o que eu usei no meu projeto:

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

E funcionou em todos os cenários

Pirata
fonte
1
Em que contexto o TextWatcher é necessário? O KeyListener era tudo que eu precisava.
precisa saber é o seguinte
@ AlanKley: Precisamos de eventos alterados antes e depois do texto para calcular o número de linhas do editText. Como se continuássemos inserindo texto e não pressionássemos a tecla "nova linha", onKey não disparava e o cursor se movia para a próxima linha automaticamente. Então, para rastrear esse tipo de linha, precisamos do textWatcher. Espero ser capaz de fazer você entender.
Pirate
Entendo. Obrigado por esse esclarecimento.
precisa saber é o seguinte
@ AlanKley Se você acha que minha resposta é útil, vote nela.
Pirate
public void afterTextChanged (Arg0 editável) {int lineCount = editText.getLineCount (); if (lineCount> numberOfLines) {editText.setText (text); }} lançará um StackOverflowException ... #
287
4

definir editText android:inputType="text"

Vimal Prabhu
fonte
3

Solução mais simples:

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
fonte
3
android:inputType="text" (or something different to "none")
android:maxLines="1"  (and this line)
Adrián Prieto
fonte
2

essa é uma abordagem. Pode ajudar alguém.

android:lines="1"
android:maxLines="1"
android:inputType="text
mohammed nathar
fonte
1

Outra maneira de limitar sua EditTextlinha a uma é a seguinte:

editText2.setTransformationMethod(new SingleLineTransformationMethod());

Observe que, após aplicar esse método de transformação, a tecla Enter cria espaços quando pressionada. Isso ainda satisfaz a pergunta de TS.

giorgos.nl
fonte
Ótima maneira de esconder nova linha! No valor, no entanto, ainda haverá um caractere de 'nova linha' !!
Gregory Stein
1

Você pode limitar seu texto de acordo com o número de linhas que eu digo, em torno de 37 alfabetos em uma linha

<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"/>
nafees ahmed
fonte
0

getLineCount () é uma opção; se você quiser valores diferentes de zero, verifique se sua visualização é medida. Para o teclado virtual, o onKeyListener não funcionará; portanto, você deve adicionar addTextChangedListener () que acompanhará as alterações de texto enquanto você digita. Assim que você receber linhas suficientes em seus retornos de chamada, faça o que você quiser para limitar: exclua caracteres com getText (), setText () ou algo mais sofisticado. Você pode até limitar o número de caracteres usando um filtro.

Outra opção é monitorar o tamanho do texto com getLineBounds (). Isso irá interagir com a gravidade do texto / paddign, portanto, tenha cuidado.

Vlad
fonte
0

Para o número limite de caracteres, podemos simplesmente usar a propriedade maxLength de EditText, pois não permitirá que o usuário insira mais caracteres.

Pirata
fonte
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" />
Atiar Talukdar
fonte
0

Outra idéia: toda vez que você digitar, o novo texto será salvo em um String lastText, apenas se o número de linhas não exceder o MAX_LINES. Nesse caso, definiríamos o texto do EditText como o último texto adicionado (para que as alterações fossem excluídas) e notificaríamos o usuário para mantê-lo curto.

 // 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();
            }
        }
    });
Amir Golan
fonte
0

Esta é uma extensão da resposta de Indrek Kõue ao Kotlin

                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)
                    }
                }
            })
Константин Казаченко
fonte
-4

Tente usar a seguinte combinação de atributos do EditText dentro do arquivo xml:

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

ihayet
fonte
2
Apenas um aviso. singleLine foi descontinuado. O maxLines foi introduzido no lugar do singleLine.
Sandeep R 23/02
@SandeepR Você está errado, android:inputTypesubstitui o uso deandroid:singleLine
Pierre