EditText maxLines no funciona: el usuario aún puede ingresar más líneas de las establecidas

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

El usuario puede ingresar más de 5 líneas, presionando la tecla enter / next row. ¿Cómo puedo limitar la entrada del usuario a una cantidad fija de filas con EditText?

Indrek Kõue
fuente
ver esta publicación: stackoverflow.com/questions/14672234/…
ali safaei

Respuestas:

84

El atributo maxLinescorresponde a la altura máxima del EditText, controla los límites exteriores y no las líneas de texto internas.

Cedekasme
fuente
Eso es lo que pensé también ... ¿Hay alguna forma de limitar las líneas incorporadas o tengo que hacerlo mediante código de fondo mediante programación?
Indrek Kõue
No hay una manera simple de limitar las líneas ingresadas como desee. Tendrás que hacerlo manualmente en tu código.
Cedekasme
3
Creo que para un desarrollador "maxLines" implica el número máximo de líneas que deberían ser posibles con editText. Si solo quisiera una altura específica, usaría "líneas". : - /
Alguien en algún lugar
241
<EditText
    android:id="@+id/edit_text"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:inputType="text"
    android:maxLines="1" 
/>

Solo necesita asegurarse de tener el atributo "inputType" establecido. No funciona sin esta línea.

android:inputType="text"
Noel Chew
fuente
3
@Neol Chew ¡Tienes razón! Trabajé después de ajustar inputTypea text. Gracias por
ahorrarme
66
@byJeevan, siempre pensé que inputType tiene un valor predeterminado de "texto". Supongo que me equivoqué.
Noel Chew el
2
Muy extraño que el texto no sea el valor predeterminado establecido para inputType, gran respuesta, sin embargo
Muhammed Refaat
9
funciona para maxLines de 1 solo pero no puede agregar una nueva línea
Daniel Raouf
68

Esto no resuelve el problema general de limitar a n líneas. Si desea limitar su EditText para tomar solo 1 línea de texto, esto puede ser muy fácil.
Puede configurar esto en el archivo xml.

android:singleLine="true"

o programáticamente

editText.setSingleLine(true);
Jesse Black
fuente
8
pero ¿qué pasa si quieres limitar a 2 filas? o 3? Para eso tienes que construir un limitador de fila personalizado ...
Indrek Kõue
44
Soy consciente de eso. "Esto no resuelve el problema general de limitar a n líneas". Terminé leyendo la pregunta aquí mientras intentaba limitarme a 1 línea y encontré una solución más fácil. Supuse que otros podrían terminar aquí buscando limitar su EditText a 1 línea e implementar el "limitador de fila personalizado". Mi respuesta está aquí para otros usuarios de SO que terminan buscando esta pregunta por la misma razón que yo.
Jesse Black el
@ IndrekKõue que no debería ser demasiado difícil.
Don
10
singleLine está en desuso
Ali
1
El atributo editText singleLine = "true" está en desuso y se bloqueará cuando los dispositivos estén usando en Android mayor que 7.0
TranHieu
24

@ Cedekasem tienes razón, no hay un "limitador de fila" incorporado. Pero construí uno yo mismo, así que si alguien está interesado, el código está debajo. Salud.

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
fuente
Esto tiene un efecto secundario no intuitivo para el usuario. por ejemplo, si tiene 7 líneas en su EditText y luego presiona enter en el medio, puede decir adiós a la última línea de su texto.
miguel.martin
no funcionará si pega más texto de maxlines en él. Así que mejor sería usar addTextChangedListener.
Kuldeep Sakhiya
13

Hice algo como ustedes han estado buscando. Aquí está miLimitedEditText clase.

caracteristicas:

  • puede limitar el recuento de líneas en su componente LimitedEditText
  • puede limitar el recuento de caracteres en su componente LimitedEditText
  • Si excede el límite de caracteres o líneas en algún lugar en el medio del texto, el cursor
    no lo llevará al final, se quedará donde ha estado.

Estoy apagando el oyente, porque cada llamada al setText()método llamaría recursivamente estos 3 métodos de devolución de llamada en caso de que el usuario excediera el límite de caracteres o líneas.

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
fuente
2
¡Esta solución es tan simple y elegante! Gracias
GuilhE
Yo uso beforeCursorPosition = getSelectionStart();en afterTextChangeddevolución de llamada. Funciona mejor porque cuando a escribir edespués de la tipificación abcd, la EditarTexto puede 'pensar' se reemplaza abcdcon abcde, debido a la entrada razón método.
hanswim
11

He hecho una solución más simple para esto: 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);
        }
    });

Puede cambiar el valor de 3 txtSpecialRequests.getLineCount() > 3a sus necesidades.

Oscar Yuandinata
fuente
3
Muchas gracias, finalmente funcionó después de múltiples soluciones incorrectas. Esta debería ser la respuesta aceptada.
eyadMhanna
Entiendo que "txtSpecialRequests" es su contenedor EditText, pero ¿dónde establece las variables lastSpecialRequestsCursorPosition y specialRequests?
drearypanoramic
fuera de este método, por supuesto :) init lastSpecialRequestsCursorPosition = 0 y specialRequests = ""
Oscar Yuandinata
Gran solución!
Marcus
5

Aquí hay un InputFilter que limita las líneas permitidas en 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 agregarlo a EditText:

editText.setFilters(new InputFilter[]{new MaxLinesInputFilter(2)});
peceps
fuente
Buena solución, sin embargo, aborda el problema del ajuste de texto (no ingresar)
Peter File
4

Esto es lo que usé en mi proyecto:

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

Y funcionó en todos los escenarios.

Pirata
fuente
1
¿Qué contexto se necesita TextWatcher? El KeyListener era todo lo que necesitaba.
AlanKley
@AlanKley: Necesitamos eventos antes y después del texto modificado para calcular el número de líneas de editText. Como si siguiéramos ingresando texto y no presionáramos la tecla "nueva línea", entonces onKey no se disparó y el cursor se movió a la siguiente línea automáticamente. Entonces, para rastrear este tipo de líneas, necesitamos textWatcher. Espero poder hacerte entender.
Pirata
Veo. Gracias por esa aclaración.
AlanKley
@AlanKley Si cree que mi respuesta es útil, vote por ella.
Pirata
public void afterTextChanged (Editable arg0) {int lineCount = editText.getLineCount (); if (lineCount> numberOfLines) {editText.setText (texto); }} lanzará una StackOverflowException ...
desgraci
4

establecer editText android:inputType="text"

Vimal Prabhu
fuente
3

La solución más simple:

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

Este es un enfoque. Podría ayudar a alguien.

android:lines="1"
android:maxLines="1"
android:inputType="text
Mohammed Nathar
fuente
1

Otra forma de limitar su EditTexta una línea es la siguiente:

editText2.setTransformationMethod(new SingleLineTransformationMethod());

Tenga en cuenta que después de aplicar este método de transformación, la tecla Intro crea espacios cuando se presiona. Eso todavía satisface la pregunta de TS.

giorgos.nl
fuente
¡Buena manera de esconder una nueva línea! ¡En el valor, sin embargo, todavía habrá un personaje de 'nueva línea'!
Gregory Stein
1

Puede limitar su texto de acuerdo con su no de líneas, digo alrededor de 37 alfabetos en una línea

<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"/>
náuseas ahmed
fuente
0

getLineCount () es una opción; si desea valores distintos de cero, asegúrese de medir su vista. Para el teclado virtual, onKeyListener no funcionará, por lo que debe agregar addTextChangedListener () que hará un seguimiento de los cambios de texto a medida que escribe. Tan pronto como obtenga suficientes líneas dentro de sus devoluciones de llamada, haga lo que quiera limitarlo: elimine caracteres con getText (), setText () o algo más elegante. Incluso puede limitar el número de caracteres usando un filtro.

Otra opción es monitorear el tamaño del texto con getLineBounds (). Esto interactuará con el texto gravedad / paddign, así que ten cuidado.

Vlad
fuente
0

Para el número límite de caracteres, simplemente podemos usar la propiedad maxLength de EditText ya que no permitirá al usuario ingresar más caracteres.

Pirata
fuente
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
fuente
0

Otra idea: cada vez que escriba, el texto nuevo se guardaría en un String lastText, solo si el número de líneas no ejecuta Exex MAX_LINES. Si lo hace, configuraríamos el texto de EditText en el último texto agregado (para que se eliminen los cambios) y notificaremos al usuario para que sea breve.

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

Esta es una extensión de la respuesta de Indrek Kõue a 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)
                    }
                }
            })
Константин Казаченко
fuente
-4

Intente usar la siguiente combinación de atributos de EditText dentro del archivo xml:

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

ihayet
fuente
2
Solo un aviso. singleLine está en desuso. maxLines se introdujo en lugar de singleLine.
Sandeep R
@SandeepR Estás equivocado, android:inputTypereemplaza el uso deandroid:singleLine
Pierre