Existe-t-il un moyen de définir une valeur minimale et maximale pour EditText dans Android?

133

Je veux définir une valeur min et max pour un EditText.

Par exemple: si une personne essaie de saisir une valeur de mois, la valeur doit être comprise entre 1 et 12.

Je peux le faire en utilisant TextWatchermais je veux savoir s'il existe un autre moyen de le faire dans un fichier de mise en page ou ailleurs.

Edit: Je ne veux pas limiter le nombre de caractères. Je veux limiter la valeur. Par exemple, si je limite le mois EditTextw caractères lorsque je saisis 12, il l'acceptera, mais si j'entre 22, il ne doit pas l'accepter pendant que j'entre.

mertaydin
la source
Quelqu'un devrait créer une bibliothèque / collection de tous ces types de filtres d'entrée. Ensuite, tout le monde peut travailler et les tester ensemble. Plutôt que chacun fasse son propre truc.
Zapnologica
Utilisez ce filtre d'édition de texte pour résoudre votre problème. filtre
Taras Smakula

Réponses:

286

Commencez par créer ce cours:

package com.test;

import android.text.InputFilter;
import android.text.Spanned;

public class InputFilterMinMax implements InputFilter {

    private int min, max;

    public InputFilterMinMax(int min, int max) {
        this.min = min;
        this.max = max;
    }

    public InputFilterMinMax(String min, String max) {
        this.min = Integer.parseInt(min);
        this.max = Integer.parseInt(max);
    }

    @Override
    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {   
        try {
            int input = Integer.parseInt(dest.toString() + source.toString());
            if (isInRange(min, max, input))
                return null;
        } catch (NumberFormatException nfe) { }     
        return "";
    }

    private boolean isInRange(int a, int b, int c) {
        return b > a ? c >= a && c <= b : c >= b && c <= a;
    }
}

Ensuite, utilisez ceci de votre activité:

EditText et = (EditText) findViewById(R.id.myEditText);
et.setFilters(new InputFilter[]{ new InputFilterMinMax("1", "12")});

Cela permettra à l'utilisateur d'entrer des valeurs de 1 à 12 uniquement .

ÉDITER :

Réglez votre edittext avec android:inputType="number".

Vous pouvez trouver plus de détails sur https://www.techcompose.com/how-to-set-minimum-and-maximum-value-in-edittext-in-android-app-development/ .

Merci.

Pratik Sharma
la source
1
@mertaydin bien sûr. essayez-le, puis faites-moi savoir si vous avez besoin de mon aide. Merci.
Pratik Sharma
12
Aah, j'ai besoin d'aide. J'ai un problème lors de l'écriture de la valeur entre 1930 et 1999. Quand j'écris 1, cela contrôle la valeur et 1 n'est pas entre 1930 et 1999, donc il ne l'accepte pas.
mertaydin
1
@mertaydin Hé désolé mais j'ai allumé un peu occupé avec mon travail. J'ai juste le temps d'examiner cela, je pense que je dois faire des modifications dans l'algorithme appliqué dans la classe de filtre. Je vous mettrai à jour une fois que j'en aurai terminé.
Pratik Sharma
1
Certains caractères de sourceremplaceront certains caractères dans dest. Je pense que vous devriez simuler le remplacement et obtenir le résultat final, puis le valider.
SD
3
@Pratik Sharma, cela ne fonctionne pas lorsque j'entre dans la plage de 1900 à 2000, pouvez-vous suggérer quelque chose
EminenT
89

Il y a une petite erreur dans le code de Pratik. Par exemple, si une valeur est 10 et que vous ajoutez un 1 au début pour faire 110, la fonction de filtre traitera la nouvelle valeur comme 101.

Voir ci-dessous pour une solution à cela:

@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
    try {
        // Remove the string out of destination that is to be replaced
        String newVal = dest.toString().substring(0, dstart) + dest.toString().substring(dend, dest.toString().length());
        // Add the new string in
        newVal = newVal.substring(0, dstart) + source.toString() + newVal.substring(dstart, newVal.length());
        int input = Integer.parseInt(newVal);
        if (isInRange(min, max, input))
            return null;
    } catch (NumberFormatException nfe) { }
    return "";
}
Zac
la source
Merci, cela m'a beaucoup aidé!
joschplusa
4
Je pense que c'est plus clair à mon humble avis :String replacement = source.subSequence(start, end).toString(); String newVal = dest.subSequence(0, dstart).toString() + replacement + dest.subSequence(dend, dest.length()).toString();
Sven Jacobs
1
+1. cette solution plus correcte qu'acceptée. Pour le vérifier, par exemple, essayez d'utiliser InputFilterMinMax avec l' option selectAllOnFocus activée et comparez le résultat.
Sash0k
1
Pourquoi pas String newVal= dest.toString().substring(0, dstart) + source.toString().substring(start, end) + dest.toString().substring(dend, dest.toString().length());, semble plus propre et plus clair.
Shishir Gupta
5
Comme mentionné par OP @mertaydin dans un commentaire sur la réponse de @Patrick, cette solution a toujours un défaut majeur, je me demande pourquoi elle n'a pas été signalée: si min==3alors il est impossible de taper un nombre commençant par 1 ou 2 (ex: 15, 23)
Guerneen4
10

De ce que j'ai vu de la solution de @ Patrik et de l'ajout de @ Zac, le code fourni a encore un gros problème:

Si min==3alors il est impossible de taper un nombre commençant par 1 ou 2 (ex: 15, 23)
Si min>=10alors il est impossible de taper quoi que ce soit car chaque nombre devra commencer par 1,2,3 ...

Dans ma compréhension, nous ne pouvons pas atteindre la limitation min-max de EditTextla valeur d'un avec une simple utilisation de la classe InputFilterMinMax, du moins pas pour la valeur min, car lorsque l'utilisateur tape un nombre positif, la valeur augmente et nous pouvons facilement effectuer un test à la volée pour vérifier s'il a atteint la limite ou s'il est sorti de la plage et bloquer les entrées non conformes. Tester la valeur minimale est une autre histoire car nous ne pouvons pas être sûrs si l'utilisateur a fini de taper ou non et ne peut donc pas décider si nous devons bloquer ou non.

Ce n'est pas exactement ce que OP a demandé, mais à des fins de validation, j'ai combiné dans ma solution un InputFilterpour tester les valeurs maximales, avec un OnFocusChangeListenerpour re-tester la valeur min lorsque EditTextperd le focus en supposant que l'utilisateur a fini de taper et que c'est quelque chose comme ceci:

package test;


import android.text.InputFilter;

import android.text.Spanned;

public class InputFilterMax implements InputFilter {

private int max;

public InputFilterMax(int max) {
    this.max = max;
}

public InputFilterMax(String max) {
    this.max = Integer.parseInt(max);
}

@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {   
    try {
        String replacement = source.subSequence(start, end).toString(); 

        String newVal = dest.toString().substring(0, dstart) + replacement +dest.toString().substring(dend, dest.toString().length());

        int input = Integer.parseInt(newVal);

        if (input<=max)
            return null;
    } catch (NumberFormatException nfe) { }   
//Maybe notify user that the value is not good      
return "";
}
}

Et OnFocusChangeListenerMin

package test;

import android.text.TextUtils;
import android.view.View;
import android.view.View.OnFocusChangeListener;

public class OnFocusChangeListenerMin implements OnFocusChangeListener {

private int min;

public OnFocusChangeListenerMin(int min) {
    this.min = min;
}

public OnFocusChangeListenerMin(String min) {
    this.min = Integer.parseInt(min);
}


@Override
public void onFocusChange(View v, boolean hasFocus) {
    if(!hasFocus) {
        String val = ((EditText)v).getText().toString();
        if(!TextUtils.isEmpty(val)){
            if(Integer.valueOf(val)<min){
                //Notify user that the value is not good
            }

        }
    }
}
}

Ensuite, dans Activité, réglez le InputFilterMaxet le OnFocusChangeListenerMinà EditText noter: Vous pouvez 2 à la fois min et max in onFocusChangeListener.

mQteEditText.setOnFocusChangeListener( new OnFocusChangeListenerMin('20');
mQteEditText.setFilters(new InputFilter[]{new InputFilterMax(getActivity(),'50')});
Guerneen4
la source
OnFocusChangeListenerMin ne fonctionne pas, il a mis toutes les valeurs à partir de zéro
EminenT
1
Cela vous dérangerait-il de détailler un peu plus? que voulez-vous dire mettre toutes les valeurs à partir de zéro ?
Guerneen4
du code OnFocusChangeListenerMin doit fonctionner au-dessus de 20 comme discuté dans le problème mais il accepte toutes les valeurs inférieures à 20 comme 0, 1, 2, ------ 19 etc
EminenT
avez-vous trouvé une solution?
EminenT
J'ai utilisé OnFoncusChangeListener dans un but de validation, dans mon cas j'affiche une erreur sur EditText avertir l'utilisateur par un Toast que la valeur n'est pas bonne et l'inviter à entrer une nouvelle valeur if(Integer.valueOf(val)<min){ //Notify user that the value is not good } Vous pouvez y faire ce que vous voulez, notifier le utilisateur et définissez EditText sur vide, je ne sais pas si cela répond à votre question
Guerneen4
9

Extension de la réponse de Pratik et Zac. Zac a corrigé un petit bug de Pratik dans sa réponse. Mais j'ai noté que le code ne prend pas en charge les valeurs négatives, il lèvera une NumberFormatException. Pour résoudre ce problème et autoriser le MIN à être négatif, utilisez le code suivant.

Ajoutez cette ligne (en gras) entre les deux autres lignes:

newVal = newVal.substring (0, dstart) + source.toString () + newVal.substring (dstart, newVal.length ());

if (newVal.equalsIgnoreCase ("-") && min <0) return null;

int entrée = Integer.parseInt (newVal);

public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
    try {
        // Remove the string out of destination that is to be replaced
        String newVal = dest.toString().substring(0, dstart) + dest.toString().substring(dend, dest.toString().length());
        // Add the new string in
        newVal = newVal.substring(0, dstart) + source.toString() + newVal.substring(dstart, newVal.length());
        //****Add this line (below) to allow Negative values***// 
        if(newVal.equalsIgnoreCase("-") && min < 0)return null;
        int input = Integer.parseInt(newVal);
        if (isInRange(min, max, input))
            return null;
    } catch (NumberFormatException nfe) {
        nfe.printStackTrace();
    }
    return "";
}
Anthony B
la source
5

Si vous avez besoin d'une plage avec des nombres négatifs comme -90: 90, vous pouvez utiliser cette solution.

public class InputFilterMinMax implements InputFilter {

private int min, max;

public InputFilterMinMax(int min, int max) {
    this.min = min;
    this.max = max;
}

public InputFilterMinMax(String min, String max) {
    this.min = Integer.parseInt(min);
    this.max = Integer.parseInt(max);
}

@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
    try {
        String stringInput = dest.toString() + source.toString();
        int value;
        if (stringInput.length() == 1 && stringInput.charAt(0) == '-') {
            value = -1;
        } else {
            value = Integer.parseInt(stringInput);
        }
        if (isInRange(min, max, value))
            return null;
    } catch (NumberFormatException nfe) {
    }
    return "";
}

private boolean isInRange(int min, int max, int value) {
    return max > min ? value >= min && value <= max : value >= max && value <= min;
}
}
Denys Vasylenko
la source
5

J'ai étendu le code @Pratik Sharmas pour utiliser des objets BigDecimal au lieu de ints afin qu'il puisse accepter des nombres plus grands et tenir compte de tout formatage dans EditText qui n'est pas un nombre (comme le formatage des devises, c'est-à-dire des espaces, des virgules et des points)

EDIT: notez que cette implémentation a 2 comme chiffres significatifs minimum définis sur le BigDecimal (voir la constante MIN_SIG_FIG) car je l'ai utilisé pour la devise, il y avait donc toujours 2 nombres en tête avant le point décimal. Modifiez la constante MIN_SIG_FIG si nécessaire pour votre propre implémentation.

public class InputFilterMinMax implements InputFilter {
private static final int MIN_SIG_FIG = 2;
private BigDecimal min, max;

public InputFilterMinMax(BigDecimal min, BigDecimal max) {
    this.min = min;
    this.max = max;
}

public InputFilterMinMax(String min, String max) {
    this.min = new BigDecimal(min);
    this.max = new BigDecimal(max);
}

@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart,
        int dend) {
    try {
        BigDecimal input = formatStringToBigDecimal(dest.toString()
                + source.toString());

        if (isInRange(min, max, input)) {

            return null;
        }
    } catch (NumberFormatException nfe) {

    }
    return "";
}

private boolean isInRange(BigDecimal a, BigDecimal b, BigDecimal c) {
    return b.compareTo(a) > 0 ? c.compareTo(a) >= 0 && c.compareTo(b) <= 0
            : c.compareTo(b) >= 0 && c.compareTo(a) <= 0;
}

public static BigDecimal formatStringToBigDecimal(String n) {

    Number number = null;
    try {
        number = getDefaultNumberFormat().parse(n.replaceAll("[^\\d]", ""));

        BigDecimal parsed = new BigDecimal(number.doubleValue()).divide(new BigDecimal(100), 2,
                BigDecimal.ROUND_UNNECESSARY);
        return parsed;
    } catch (ParseException e) {
        return new BigDecimal(0);
    }
}

private static NumberFormat getDefaultNumberFormat() {
    NumberFormat nf = NumberFormat.getInstance(Locale.getDefault());
    nf.setMinimumFractionDigits(MIN_SIG_FIG);
    return nf;
}
AndroidNoob
la source
4

J'ai trouvé ma propre réponse. Il est très tard maintenant mais je veux le partager avec vous. J'implémente cette interface:

import android.text.TextWatcher;


public abstract class MinMaxTextWatcher implements TextWatcher {
    int min, max;
    public MinMaxTextWatcher(int min, int max) {
        super();
        this.min = min;
        this.max = max;
    }

}

Et puis implémentez-le de cette manière dans votre activité:

private void limitEditText(final EditText ed, int min, int max) {
    ed.addTextChangedListener(new MinMaxTextWatcher(min, max) {
        @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) {
            String str = s.toString();
            int n = 0;
            try {
                n = Integer.parseInt(str);
                if(n < min) {
                    ed.setText(min);
                    Toast.makeText(getApplicationContext(), "Minimum allowed is " + min, Toast.LENGTH_SHORT).show();
                }
                else if(n > max) {
                    ed.setText("" + max);
                    Toast.makeText(getApplicationContext(), "Maximum allowed is " + max, Toast.LENGTH_SHORT).show();
                }
            }
            catch(NumberFormatException nfe) {
                ed.setText("" + min);
                Toast.makeText(getApplicationContext(), "Bad format for number!" + max, Toast.LENGTH_SHORT).show();
            }
        }
    });
}

C'est une réponse très simple, s'il vous plaît, dites-moi.

Nash Makineta
la source
int n = 0; est redondant. Puisque la valeur par défaut de n est 0.
Kenny Dabiri
1
Pourquoi int n = 0 est-il redondant ici? c'est une variable locale et non une variable d'instance ici.
User12111111
4

Il y a quelque chose qui ne va pas dans la réponse acceptée.

int input = Integer.parseInt(dest.toString() + source.toString());

Si je déplace le curseur au milieu du texte, puis tapez quelque chose, l'instruction ci-dessus produira un résultat erroné. Par exemple, tapez d'abord «12», puis tapez «0» entre 1 et 2, puis l'instruction mentionnée ci-dessus produira «120» au lieu de 102. J'ai modifié cette instruction en instructions ci-dessous:

String destString = dest.toString();
  String inputString = destString.substring(0, dstart) + source.toString() + destString.substring(dstart);
  int input = Integer.parseInt(inputString);
谭春茂
la source
4

Kotlin si quelqu'un en a besoin (utiliser des utilitaires)

class InputFilterMinMax: InputFilter {
    private var min:Int = 0
    private var max:Int = 0
    constructor(min:Int, max:Int) {
        this.min = min
        this.max = max
    }
    constructor(min:String, max:String) {
        this.min = Integer.parseInt(min)
        this.max = Integer.parseInt(max)
    }
    override fun filter(source:CharSequence, start:Int, end:Int, dest: Spanned, dstart:Int, dend:Int): CharSequence? {
        try
        {
            val input = Integer.parseInt(dest.toString() + source.toString())
            if (isInRange(min, max, input))
                return null
        }
        catch (nfe:NumberFormatException) {}
        return ""
    }
    private fun isInRange(a:Int, b:Int, c:Int):Boolean {
        return if (b > a) c in a..b else c in b..a
    }
}

Ensuite, utilisez ceci de votre classe Kotlin

percentage_edit_text.filters = arrayOf(Utilities.InputFilterMinMax(1, 100))

Cet EditText permet de 1 à 100.

Ensuite, utilisez ceci à partir de votre XML

android:inputType="number"
Alish
la source
J'utilise la source de retour et je travaille pour moi ==> if (isInRange (min, max, input)) return source
Muzafferus
3

J'ai fait un moyen plus simple de définir un min / max sur un Edittext. J'utilise le clavier arithmétique et je travaille avec cette méthode:

 private int limit(EditText x,int z,int limin,int limax){

    if( x.getText().toString()==null || x.getText().toString().length()==0){
        x.setText(Integer.toString(limin));
        return z=0;
    }
    else{
        z = Integer.parseInt(x.getText().toString());
         if(z <limin || z>limax){
             if(z<10){
                 x.setText(Integer.toString(limin));
                return  z=0;
             }
            else{
                x.setText(Integer.toString(limax));
                return z=limax;
            }

         }
         else
            return z = Integer.parseInt(x.getText().toString());
    }
 }

La méthode accepte toutes vos valeurs, mais si une valeur d'utilisateurs ne respecte pas vos limites, elle sera automatiquement définie sur la limite min / max. Par ex. limit limin = 10, limax = 80 si l'utilisateur définit 8, automatiquement 10 est enregistré dans une variable et EditText est défini sur 10.

Argyris
la source
3

Je sais qu'il y a déjà un million de réponses à cela, dont une acceptée. Cependant, il existe de nombreux bogues dans la réponse acceptée et la plupart des autres en corrigent simplement un (ou peut-être deux), sans s'étendre à tous les cas d'utilisation possibles.

J'ai donc compilé la plupart des corrections de bogues suggérées dans les réponses de support ainsi que l'ajout d'une méthode pour permettre l'entrée continue de nombres en dehors de la plage dans la direction de 0 (si la plage ne commence pas à 0), du moins jusqu'à ce qu'elle soit certain qu'il ne peut plus être dans la plage. Parce que pour être clair, c'est le seul moment qui cause vraiment des problèmes avec de nombreuses autres solutions.

Voici la solution:

public class InputFilterIntRange implements InputFilter, View.OnFocusChangeListener {

    private final int min, max;

    public InputFilterIntRange(int min, int max) {
        if (min > max) {
            // Input sanitation for the filter itself
            int mid = max;
            max = min;
            min = mid;
        }
        this.min = min;
        this.max = max;
    }

    @Override
    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {

        // Determine the final string that will result from the attempted input
        String destString = dest.toString();
        String inputString = destString.substring(0, dstart) + source.toString() + destString.substring(dstart);

        // Don't prevent - sign from being entered first if min is negative
        if (inputString.equalsIgnoreCase("-") && min < 0) return null;

        try {
            int input = Integer.parseInt(inputString);
            if (mightBeInRange(input))
                return null;
        } catch (NumberFormatException nfe) {}

        return "";
    }

    @Override
    public void onFocusChange(View v, boolean hasFocus) {

        // Since we can't actively filter all values
        // (ex: range 25 -> 350, input "15" - could be working on typing "150"),
        // lock values to range after text loses focus
        if (!hasFocus) {
            if (v instanceof EditText) sanitizeValues((EditText) v);
        }
    }

    private boolean mightBeInRange(int value) {
        // Quick "fail"
        if (value >= 0 && value > max) return false;
        if (value >= 0 && value >= min) return true;
        if (value < 0 && value < min) return false;
        if (value < 0 && value <= max) return true;

        boolean negativeInput = value < 0;

        // If min and max have the same number of digits, we can actively filter
        if (numberOfDigits(min) == numberOfDigits(max)) {
            if (!negativeInput) {
                if (numberOfDigits(value) >= numberOfDigits(min) && value < min) return false;
            } else {
                if (numberOfDigits(value) >= numberOfDigits(max) && value > max) return false;
            }
        }

        return true;
    }

    private int numberOfDigits(int n) {
        return String.valueOf(n).replace("-", "").length();
    }

    private void sanitizeValues(EditText valueText) {
        try {
            int value = Integer.parseInt(valueText.getText().toString());
            // If value is outside the range, bring it up/down to the endpoint
            if (value < min) {
                value = min;
                valueText.setText(String.valueOf(value));
            } else if (value > max) {
                value = max;
                valueText.setText(String.valueOf(value));
            }
        } catch (NumberFormatException nfe) {
            valueText.setText("");
        }
    }

}

Notez que certains cas de saisie sont impossibles à gérer "activement" (c'est-à-dire lorsque l'utilisateur le saisit), nous devons donc les ignorer et les gérer une fois que l'utilisateur a fini de modifier le texte.

Voici comment vous pourriez l'utiliser:

EditText myEditText = findViewById(R.id.my_edit_text);
InputFilterIntRange rangeFilter = new InputFilterIntRange(25, 350);
myEditText.setFilters(new InputFilter[]{rangeFilter});

// Following line is only necessary if your range is like [25, 350] or [-350, -25].
// If your range has 0 as an endpoint or allows some negative AND positive numbers, 
// all cases will be handled pre-emptively.
myEditText.setOnFocusChangeListener(rangeFilter);

Maintenant, lorsque l'utilisateur essaie de taper un nombre plus proche de 0 que la plage le permet, l'une des deux choses suivantes se produit:

  1. Si minet maxont le même nombre de chiffres, ils ne seront pas autorisés à le saisir du tout une fois qu'ils auront atteint le dernier chiffre.

  2. Si un nombre en dehors de la plage est laissé dans le champ lorsque le texte perd le focus, il sera automatiquement ajusté à la limite la plus proche.

Et bien sûr, l'utilisateur ne sera jamais autorisé à entrer une valeur plus éloignée de 0 que la plage le permet, et il n'est pas non plus possible pour un nombre comme celui-là d'être "accidentellement" dans le champ de texte pour cette raison.

Problèmes connus?)

  1. Cela ne fonctionne que si le EditTextperd le focus lorsque l'utilisateur en a terminé avec lui.

L'autre option consiste à nettoyer lorsque l'utilisateur appuie sur la touche «terminé» / retour, mais dans de nombreux cas, voire dans la plupart des cas, cela provoque de toute façon une perte de concentration.

Cependant, la fermeture du clavier virtuel ne désactive pas automatiquement la mise au point de l'élément. Je suis sûr que 99,99% des développeurs Android le souhaiteraient (et cette concentration sur la gestion des EditTextéléments était moins un bourbier en général), mais pour l'instant, il n'y a pas de fonctionnalité intégrée pour cela. La méthode la plus simple que j'ai trouvée pour contourner ce problème, si vous en avez besoin, est d'étendre EditTextquelque chose comme ceci:

public class EditTextCloseEvent extends AppCompatEditText {

    public EditTextCloseEvent(Context context) {
        super(context);
    }

    public EditTextCloseEvent(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public EditTextCloseEvent(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public boolean onKeyPreIme(int keyCode, KeyEvent event) {
        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
            for (InputFilter filter : this.getFilters()) {
                if (filter instanceof InputFilterIntRange)
                    ((InputFilterIntRange) filter).onFocusChange(this, false);
            }
        }
        return super.dispatchKeyEvent(event);
    }
}

Cela "trompera" le filtre en nettoyant l'entrée même si la vue n'a pas réellement perdu le focus. Si la vue perd par la suite le focus d'elle-même, l'assainissement d'entrée se déclenchera à nouveau, mais rien ne changera car il a déjà été corrigé.

Fermeture

Ouf. C'était beaucoup. Ce qui semblait à l'origine être un problème assez trivial a fini par découvrir de nombreux petits morceaux laids d'Android vanille (du moins en Java). Et encore une fois, il vous suffit d'ajouter l'écouteur et de l'étendre EditTextsi votre plage n'inclut pas 0 d'une manière ou d'une autre. (Et de manière réaliste, si votre plage n'inclut pas 0 mais commence à 1 ou -1, vous ne rencontrerez pas non plus de problèmes.)

En dernier lieu, cela ne fonctionne que pour les ints . Il existe certainement un moyen de l'implémenter pour travailler avec des décimales ( double, float), mais comme ni moi ni le demandeur d'origine n'en avons besoin, je ne veux pas particulièrement approfondir tout cela. Il serait très facile d'utiliser simplement le filtrage post-achèvement avec les lignes suivantes:

// Quick "fail"
if (value >= 0 && value > max) return false;
if (value >= 0 && value >= min) return true;
if (value < 0 && value < min) return false;
if (value < 0 && value <= max) return true;

Il vous suffirait de changer de intà float(ou double), d'autoriser l'insertion d'un seul .(ou ,, selon le pays?), Et d'analyser comme l'un des types décimaux au lieu d'un int.

Cela gère la plupart du travail de toute façon, donc cela fonctionnerait de manière très similaire.

VerumCH
la source
2
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
    try {
        String prefix = dest.toString().substring(0, dstart);
        String insert = source.toString();
        String suffix = dest.toString().substring(dend);
        String input_string = prefix + insert + suffix;
        int input = Integer.parseInt(input_string);

        if (isInRange(min, max, input) || input_string.length() < String.valueOf(min).length())
            return null;
    } catch (NumberFormatException nfe) { }
    return "";
}

private boolean isInRange(int a, int b, int c) {
    return b > a ? c >= a && c <= b : c >= b && c <= a;
}
jet27
la source
2

Exemple très simple sur Kotlin:

import android.text.InputFilter
import android.text.Spanned

class InputFilterRange(private var range: IntRange) : InputFilter {

    override fun filter(source: CharSequence, start: Int, end: Int, dest: Spanned, dstart: Int, dend: Int) = try {
        val input = Integer.parseInt(dest.toString() + source.toString())
        if (range.contains(input)) null else ""
    } catch (nfe: NumberFormatException) {
        ""
    }
}
Andrew
la source
1

veuillez vérifier ce code

    String pass = EditText.getText().toString(); 
    if(TextUtils.isEmpty(pass) || pass.length < [YOUR MIN LENGTH]) 
    { 
       EditText.setError("You must have x characters in your txt"); 
        return; 
    }

    //continue processing



edittext.setOnFocusChangeListener( new OnFocusChangeListener() {

       @Override
       public void onFocusChange(View v, boolean hasFocus) {
          if(hasFocus) {
           // USE your code here 
  }

Utilisez le lien ci-dessous pour plus de détails sur edittext et les edittextfilteres avec text watcher.

http://www.mobisoftinfotech.com/blog/android/android-edittext-setfilters-example-numeric-text-field-patterns-and-length-restriction/

itsrajesh4uguys
la source
OP veut le valider lors de la saisie de la valeur. Je pense que vous avez fourni une solution pour le scénario après la saisie de la valeur
MysticMagicϡ
Je ne suis pas celui qui pose la question. J'avais juste un doute sur votre réponse, alors je la clarifiais.
MysticMagicϡ
Je ne veux pas vérifier le nombre de caractères. Je pense que vous essayez de vérifier le nombre dans ce code: if (TextUtils.isEmpty (pass) || pass.length <[YOUR MIN LENGTH]) Je limite juste la valeur par exemple pour la valeur du mois, l'utilisateur doit écrire la valeur entre 1-12 et non 13,14, ou etc. Donc, 12,13,14, jusqu'à ce que 99 soit une longueur de 2 caractères.
mertaydin
salut @mertaydin avez-vous essayé avec le lien que je vous ai fourni .. voir cet exemple .. peut-être c'est ce que vous voulez. il regardera le texte pendant que vous entrez ..
itsrajesh4uguys
Ok merci, je vais essayer votre réponse et la réponse de @Pratik Sharma.
mertaydin
1

Si vous n'êtes préoccupé que par la limite maximale, ajoutez simplement la ligne ci-dessous dans

android:maxLength="10" 

Si vous avez besoin d'ajouter une limite minimale, vous pouvez faire comme ceci dans ce cas, la limite minimale est de 7. l'utilisateur est limité à entrer un caractère entre la limite min et max (entre 8 et 10)

public final static boolean isValidCellPhone(String number){
        if (number.length() < 8 || number.length() >10 ) {
            return false;
        } else {

           return android.util.Patterns.PHONE.matcher(number).matches();
        }
    }

Si vous devez également restreindre l'utilisateur à entrer 01 au début, modifiez si la condition comme ceci

if (!(number.startsWith("01")) || number.length() < 8 || number.length() >10 ) {  
.
.
.
}

À la fin de la méthode d'appel comme

   ....else if (!(Helper.isValidMobilePhone(textMobileNo))){
                        Helper.setEditTextError(etMobileNo,"Invalid Mobile Number");
                    }......
Faakhir
la source
2
Ce n'est pas vlaue, c'est la longueur
portfoliobuilder
1

@Pratik Sharma

Pour prendre en charge les nombres négatifs , ajoutez le code suivant dans la méthode de filtrage :

package ir.aboy.electronicarsenal;

import android.text.InputFilter;
import android.text.Spanned;

public class InputFilterMinMax implements InputFilter {

  private int min, max;
  int input;

  InputFilterMinMax(int min, int max) {
    this.min = min;
    this.max = max;
  }

  public InputFilterMinMax(String min, String max) {
    this.min = Integer.parseInt(min);
    this.max = Integer.parseInt(max);
  }

  @Override
  public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
    try {

      if ((dest.toString() + source.toString()).equals("-")) {
        source = "-1";
      }

      input = Integer.parseInt(dest.toString() + source.toString());
      if (isInRange(min, max, input))
        return null;

    } catch (NumberFormatException ignored) {
    }
    return "";
  }

  private boolean isInRange(int a, int b, int c) {
    return b > a ? c >= a && c <= b : c >= b && c <= a;
  }

}

Ensuite, utilisez ceci de votre activité:

findViewById(R.id.myEditText).setFilters(new InputFilter[]{ new InputFilterMinMax(1, 12)});

Réglez votre edittext avec:

android:inputType="number|numberSigned"
gadolf
la source
0

// a encore un problème mais ici vous pouvez utiliser min, max à n'importe quelle plage (positive ou négative)

// in filter calss
 @Override
 public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
        try {
            // Remove the string out of destination that is to be replaced
            int input;
            String newVal = dest.toString() + source.toString();
            if (newVal.length() == 1 && newVal.charAt(0) == '-') {
                input = min; //allow
            }
            else {
                newVal = dest.toString().substring(0, dstart) + dest.toString().substring(dend, dest.toString().length());
                // Add the new string in
                newVal = newVal.substring(0, dstart) + source.toString() + newVal.substring(dstart, newVal.length());
                input = Integer.parseInt(newVal);
            }

            //int input = Integer.parseInt(dest.toString() + source.toString());

            if (isInRange(min, max, input))
                return null;
        } catch (NumberFormatException nfe) {
        }
        return "";
    }

//also the filler must set as below: in the edit createview
// to allow enter number and backspace.
et.setFilters(new InputFilter[]{new InputFilterMinMax(min >= 10 ?  "0" : String.valueOf(min), max >-10 ? String.valueOf(max) :"0" )});



//and at same time must check range in the TextWatcher()
et.addTextChangedListener(new
 TextWatcher() {

      @Override
      public void afterTextChanged (Editable editable)
      {
         String tmpstr = et.getText().toString();
         if (!tmpstr.isEmpty() && !tmpstr.equals("-") ) {
             int datavalue = Integer.parseInt(tmpstr);
             if ( datavalue >= min || datavalue <= max) {
               // accept data ...     
             }
         }
      }
 });
CHTsai
la source
0

Pour ajouter à la réponse de Pratik, voici une version modifiée où l'utilisateur peut également saisir au moins 2 chiffres, par exemple 15 à 100:

 import android.text.InputFilter;
 import android.text.Spanned;

public class InputFilterMinMax implements InputFilter {

    private int min, max;

    public InputFilterMinMax(int min, int max) {
        this.min = min;
        this.max = max;
    }

    public InputFilterMinMax(String min, String max) {
        this.min = Integer.parseInt(min);
        this.max = Integer.parseInt(max);
    }

    @Override
    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {

        try {
            if(end==1)
                min=Integer.parseInt(source.toString());
            int input = Integer.parseInt(dest.toString() + source.toString());
            if (isInRange(min, max, input))
                return null;
        } catch (NumberFormatException nfe) {
        }
        return "";
    }

    private boolean isInRange(int a, int b, int c) {

        return b > a ? c >= a && c <= b : c >= b && c <= a;
    }}

ajouté: if (end == 1) min = Integer.parseInt (source.toString ());

J'espère que cela t'aides. veuillez ne pas voter sans raison.

sanjeeb
la source
0

voici la façon dont j'ai utilisé, ça marche pour un nombre négatif

Tout d'abord, créez la classe MinMaxFIlter.java avec le code suivant:

import android.text.InputFilter;
import android.text.Spanned;
import android.util.Log;

/**
* Created by 21 on 4/5/2016.
*/
public class MinMaxFilter implements InputFilter {

private double mIntMin, mIntMax;

public MinMaxFilter(double minValue, double maxValue) {
    this.mIntMin = minValue;
    this.mIntMax = maxValue;
}

public MinMaxFilter(String minValue, String maxValue) {
    this.mIntMin = Double.parseDouble(minValue);
    this.mIntMax = Double.parseDouble(maxValue);
}

@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
    try {
        Boolean isNeg = false;
        String provi = dest.toString() + source.toString();
        if("-".equals(provi.substring(0,1))){
            if(provi.length()>1) {
                provi = provi.substring(1, provi.length());
                isNeg = true;
            }
            else{
                if("".equals(source)){
                    return null;
                }
                return "-";
            }
        }

        double input = Double.parseDouble(provi); 
        if(isNeg){input = input * (-1);}

        if (isInRange(mIntMin, mIntMax, input)) {
            return null;
        }
    } catch (Exception nfe) {}
    return "";
}

private boolean isInRange(double a, double b, double c) {
    if((c>=a && c<=b)){
        return true;
    }
    else{
        return false;
    }
}
}

Ensuite, créez et définissez votre filtre sur votre edittext comme ceci:

EditText edittext = new EditText(context);
editext.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_SIGNED);
eInt.setFilters(new InputFilter[]{new MinMaxFilter(min, max)});
maloromano
la source
0

c'est mon code max = 100, min = 0

xml

<TextView
                    android:id="@+id/txt_Mass_smallWork"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:textColor="#000"
                    android:textSize="20sp"
                    android:textStyle="bold" />

Java

EditText ed = findViewById(R.id.txt_Mass_smallWork);
    ed.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {`

        }

        @Override
        public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
            if(!charSequence.equals("")) {
                int massValue = Integer.parseInt(charSequence.toString());
                if (massValue > 10) {
                    ed.setFilters(new InputFilter[]{new InputFilter.LengthFilter(2)});
                } else {
                    ed.setFilters(new InputFilter[]{new InputFilter.LengthFilter(3)});
                }
            }
        }

        @Override
        public void afterTextChanged(Editable editable) {

        }
    });
Hoàng
la source
0

Vous pouvez le faire avec un InputFilter. Apparemment, il n'y a que cette interface de filtre d'entrée que vous pouvez utiliser. Avant de le faire de manière ennuyeuse et de créer une nouvelle classe qui étend le filtre d'entrée, vous pouvez utiliser ce raccourci avec une instanciation d'interface de classe interne.

Par conséquent, faites simplement ceci:

EditText subTargetTime = (EditText) findViewById(R.id.my_time);
subTargetTime.setFilters( new InputFilter[] {
                new InputFilter() {
                    @Override
                    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
                        int t = Integer.parseInt(source.toString());
                        if(t <8) { t = 8; }
                        return t+"";

                    }
                }
        });

Dans cet exemple, je vérifie si la valeur de EditText est supérieure à 8. Sinon, elle doit être mise à 8. Donc, apparemment, vous devez régler vous-même le min max ou n'importe quelle logique de filtre. Mais au moins, vous pouvez écrire la logique du filtre assez nette et courte directement dans le EditText.

J'espère que cela t'aides

Christopher-Robin Fey Feysenbe
la source
0

Pour définir la valeur minimale du EditText, j'ai utilisé ceci:

if (message.trim().length() >= 1 && message.trim().length() <= 12) {
  // do stuf
} else {
  // Too short or too long
}
Bonne Bogaert
la source
0

Le code de @ Patrik a une bonne idée mais avec beaucoup de bugs. @Zac et @Anthony B (solutions de nombres négatifs) ont résolu certains d'entre eux, mais le code de @ Zac a encore 3 bugs majeurs:

1. Si l'utilisateur supprime toutes les entrées dans EditText, il est impossible de taper à nouveau un nombre. Bien sûr, cela peut être contrôlé en utilisant un écouteur modifié EditText sur chaque champ, mais cela effacera la beauté d'utiliser une classe InputFilter commune pour chaque EditText dans votre application.

2. A @ Guernee4 dit, si par exemple min = 3, il est impossible de taper un nombre commençant par 1.

3. Si par exemple min = 0, vous pouvez taper a beaucoup de zéros que vous souhaitez, que le résultat n'est pas élégant. Ou aussi, si quelle que soit la valeur minimale, l'utilisateur peut placer le curseur dans la taille gauche du premier nombre, et placer un tas de zéros non significatifs vers la gauche, également pas élégant.

Je suis venu avec ces petits changements du code de @ Zac pour résoudre ces 3 bogues. En ce qui concerne le bug n ° 3, je n'ai toujours pas pu supprimer complètement tous les zéros de gauche à gauche; Cela peut toujours être un, mais un 00, 01, 0100, etc. dans ce cas, est plus élégant et valide qu'un 000000, 001, 000100, etc. etc. Etc.

Voici le code:

@Override
    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
        try {

            // Using @Zac's initial solution
            String lastVal = dest.toString().substring(0, dstart) + dest.toString().substring(dend);
            String newVal = lastVal.substring(0, dstart) + source.toString() + lastVal.substring(dstart);
            int input = Integer.parseInt(newVal);

            // To avoid deleting all numbers and avoid @Guerneen4's case
            if (input < min && lastVal.equals("")) return String.valueOf(min);

            // Normal min, max check
            if (isInRange(min, max, input)) {

                // To avoid more than two leading zeros to the left
                String lastDest = dest.toString();
                String checkStr = lastDest.replaceFirst("^0+(?!$)", "");
                if (checkStr.length() < lastDest.length()) return "";

                return null;
            }
        } catch (NumberFormatException ignored) {}
        return "";
    }

Bonne journée!

nnyerges
la source
-1

Voici mon avis sur la réponse de Pratik Sharma Kotlinet Doublesi quelqu'un en a besoin

class InputFilterMinMax : InputFilter {

private var min: Double = MIN_LIMIT
private var max: Double = MIN_LIMIT

constructor(min: Int, max: Int) {
    this.min = min.toDouble()
    this.max = max.toDouble()
}

constructor(min: String, max: String) {
    this.min = min.toDouble()
    this.max = max.toDouble()
}

constructor(min: Double, max: Double) {
    this.min = min
    this.max = max
}

override fun filter(
    source: CharSequence,
    start: Int,
    end: Int,
    dest: Spanned,
    dstart: Int,
    dend: Int
): CharSequence? {
    try {
        val input = (dest.toString() + source.toString()).toDouble()
        if (isInRange(min, max, input))
            return null
    } catch (nfe: NumberFormatException) {
        Timber.e(nfe)
    }

    return ""
}

private fun isInRange(a: Double, b: Double, c: Double): Boolean {
    return if (b > a) c in a..b else c in b..a
}
}
Varun Barve
la source
Ce filtre d'entrée est erroné, il ignore les indices de début, de fin, de dstart, de dend du texte, donc si vous modifiez le texte d'édition en insérant un caractère au milieu, il ne fonctionnera pas correctement
Radu