EditText maxLines ne fonctionne pas - l'utilisateur peut toujours saisir plus de lignes que défini

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

L'utilisateur peut saisir plus de 5 lignes, en appuyant sur la touche Entrée / ligne suivante. Comment puis-je limiter l'entrée utilisateur à un nombre fixe de lignes avec EditText?

Indrek Kõue
la source
voir cet article: stackoverflow.com/questions/14672234/…
ali safaei

Réponses:

84

L'attribut maxLinescorrespond à la hauteur maximale du EditText, il contrôle les limites extérieures et non les lignes de texte intérieures.

Cedekasme
la source
C'est ce que j'ai pensé aussi ... Y a-t-il un moyen de limiter les lignes entrées ou dois-je le faire sur le code backend par programmation?
Indrek Kõue
Il n'y a pas de moyen simple de limiter les lignes entrées comme vous le souhaitez. Vous devrez le faire manuellement dans votre code.
Cedekasme
3
Je pense que pour un développeur "maxLines" implique le nombre maximum de lignes qui devrait être possible avec un editText. Si je voulais juste une hauteur spécifique, j'utiliserais des "lignes". : - /
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" 
/>

Vous devez simplement vous assurer que vous avez défini l'attribut "inputType". Cela ne fonctionne pas sans cette ligne.

android:inputType="text"
Noel à mâcher
la source
3
@Neol Chew Vous avez raison! J'ai travaillé après la mise inputTypeà text. Merci d'avoir économisé mon temps :-)
parJeevan
6
@byJeevan, j'ai toujours pensé que inputType avait une valeur par défaut de "text". Je suppose que j'avais tort.
Noel Chew
2
Très étrange que le texte ne soit pas la valeur par défaut définie pour inputType, bonne réponse cependant
Muhammed Refaat
9
cela fonctionne pour maxLines de 1 seulement mais vous ne pouvez pas ajouter de nouvelle ligne
Daniel Raouf
68

Cela ne résout pas le problème général de la limitation à n lignes. Si vous souhaitez limiter votre EditText à une seule ligne de texte, cela peut être très simple.
Vous pouvez définir cela dans le fichier xml.

android:singleLine="true"

ou par programmation

editText.setSingleLine(true);
Jesse Black
la source
8
mais que faire si vous voulez limiter à 2 lignes? ou 3? Pour cela, vous devez construire un limiteur de ligne personnalisé ...
Indrek Kõue
4
Je suis au courant de ça. "Cela ne résout pas le problème général de la limitation à n lignes". J'ai fini par lire la question ici pendant que j'essayais de limiter à 1 ligne et de trouver une solution plus simple. J'ai pensé que d'autres pourraient finir par chercher ici à limiter leur EditText à 1 ligne et à implémenter le "limiteur de ligne personnalisé". Ma réponse est ici pour les autres utilisateurs SO qui finissent par chercher cette question pour la même raison que moi.
Jesse Black
@ IndrekKõue ça ne devrait pas être trop dur.
Don Larynx
10
singleLine est obsolète
Ali
1
L'attribut de editText singleLine = "true" est obsolète et il va planter sur les appareils utilisent à Android plus grand que 7.0
TranHieu
24

@Cedekasem vous avez raison, il n'y a pas de "limiteur de ligne" intégré. Mais j'en ai construit un moi-même, donc si quelqu'un est intéressé, le code est ci-dessous. À votre santé.

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
la source
Cela a un effet secondaire peu intuitif pour l'utilisateur. Par exemple, si vous avez 7 lignes dans votre EditText et que vous appuyez sur Entrée au milieu de celui-ci, vous pouvez dire au revoir à la dernière ligne de votre texte.
miguel.martin
ne fonctionnera pas si vous y collez plus de maxlines de texte. Il vaut donc mieux utiliser addTextChangedListener.
Kuldeep Sakhiya
13

J'ai fait quelque chose comme vous cherchiez. Voici ma LimitedEditTextclasse.

Fonctionnalités:

  • vous pouvez limiter le nombre de lignes dans votre composant LimitedEditText
  • vous pouvez limiter le nombre de caractères dans votre composant LimitedEditText
  • si vous dépassez la limite de caractères ou de lignes quelque part au milieu du texte, le curseur
    ne vous amènera pas à la fin - il restera où vous étiez.

Je désactive l'écouteur, car chaque appel de setText()méthode appelle de manière récursive ces 3 méthodes de rappel au cas où l'utilisateur dépasserait la limite de caractères ou de lignes.

Code:

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
la source
2
Cette solution est si simple et élégante! Merci
GuilhE
J'utilise beforeCursorPosition = getSelectionStart();en afterTextChangedcallback. Cela fonctionne mieux car lors de la saisie eaprès la saisie abcd, le EditText peut «penser» que vous remplacez abcdpar abcde, en raison de la raison de la méthode d'entrée.
hanswim
11

J'ai fait une solution plus simple pour cela: 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);
        }
    });

Vous pouvez modifier la valeur de 3 en fonction txtSpecialRequests.getLineCount() > 3de vos besoins.

Oscar Yuandinata
la source
3
Merci beaucoup, enfin travaillé après plusieurs mauvaises solutions. Cela devrait être la réponse acceptée.
eyadMhanna
J'obtiens que "txtSpecialRequests" est votre conteneur EditText, mais où définissez-vous les variables lastSpecialRequestsCursorPosition et specialRequests?
drearypanoramic
en dehors de cette méthode bien sûr :) init lastSpecialRequestsCursorPosition = 0 et specialRequests = ""
Oscar Yuandinata
Excellente solution!
Marcus
5

Voici un InputFilter qui limite les lignes autorisées dans 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;
  }
}

Pour l'ajouter à EditText:

editText.setFilters(new InputFilter[]{new MaxLinesInputFilter(2)});
peceps
la source
Bonne solution, mais elle résout le problème de l'habillage du texte (pas de saisie)
Peter File
4

C'est ce que j'ai utilisé dans mon projet:

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

Et cela a fonctionné dans tous les scénarios

Pirate
la source
1
De quel contexte le TextWatcher a-t-il besoin? Le KeyListener était tout ce dont j'avais besoin.
AlanKley
@AlanKley: Nous avons besoin d'événements avant et après le changement de texte pour calculer le nombre de lignes de editText. Comme si nous continuions à saisir du texte et n'appuyions pas sur la touche "nouvelle ligne", onKey ne se déclenchait pas et le curseur passait automatiquement à la ligne suivante. Donc, pour suivre ce type de lignes, nous avons besoin de textWatcher. J'espère pouvoir vous faire comprendre.
Pirate
Je vois. Merci pour cette clarification.
AlanKley
@AlanKley Si vous pensez que ma réponse est utile, veuillez voter pour elle.
Pirate
public void afterTextChanged (Arg0 modifiable) {int lineCount = editText.getLineCount (); if (lineCount> numberOfLines) {editText.setText (texte); }} lancera une StackOverflowException ...
desgraci
4

définir editText android:inputType="text"

Vimal Prabhu
la source
3

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

c'est une approche. Pourrait aider quelqu'un.

android:lines="1"
android:maxLines="1"
android:inputType="text
mohammed nathar
la source
1

Une autre façon de limiter votre EditTextà une ligne est la suivante:

editText2.setTransformationMethod(new SingleLineTransformationMethod());

Notez qu'après avoir appliqué cette méthode de transformation, la touche Entrée crée des espaces lorsqu'elle est enfoncée. Cela satisfait toujours la question de TS.

giorgos.nl
la source
Belle façon de cacher la nouvelle ligne! Dans la valeur, cependant, il y aura toujours un caractère «nouvelle ligne» !!
Gregory Stein
1

Vous pouvez limiter votre texte en fonction de votre nombre de lignes, je dis environ 37 alphabets en une seule ligne

<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
la source
0

getLineCount () est une option; si vous voulez des valeurs non nulles, assurez-vous que votre vue est mesurée. Pour le clavier logiciel, onKeyListener ne fonctionnera pas, vous devez donc ajouter addTextChangedListener () qui suivra les modifications de texte au fur et à mesure que vous tapez. Dès que vous avez suffisamment de lignes dans ses rappels, faites ce que vous voulez pour le limiter: supprimez les caractères avec getText (), setText () ou quelque chose de plus sophistiqué. Vous pouvez même limiter le nombre de caractères à l'aide d'un filtre.

Une autre option consiste à surveiller la taille du texte avec getLineBounds (). Cela interagira avec la gravité du texte / paddign alors soyez prudent.

Vlad
la source
0

Pour un nombre limité de caractères, nous pouvons simplement utiliser la propriété maxLength de EditText car elle ne permettra pas à l'utilisateur d'entrer plus de caractères.

Pirate
la source
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
la source
0

Autre idée: à chaque fois après la saisie, le nouveau texte serait enregistré dans un String lastText, uniquement si le nombre de lignes n'excède pas les MAX_LINES. Si c'est le cas, nous définirions le texte de EditText sur le dernier texte ajouté (de sorte que les modifications seraient supprimées) et informerions l'utilisateur de le garder court.

 // 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
la source
0

Ceci est une extension de la réponse d' Indrek Kõue à 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)
                    }
                }
            })
Константин Казаченко
la source
-4

Essayez d'utiliser la combinaison suivante d'attributs du EditText dans le fichier xml:

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

ihayet
la source
2
Juste un avertissement. singleLine est obsolète. maxLines a été introduit à la place de singleLine.
Sandeep R
@SandeepR Vous vous trompez, android:inputTyperemplace l'utilisation deandroid:singleLine
Pierre