1. Nimm jetzt an unserem Uhans - 3. ADVENT - Gewinnspiel teil - Alle Informationen findest Du hier!

InputFilter auf EditText - Zahlen nicht größer als 100

Dieses Thema im Forum "Android App Entwicklung" wurde erstellt von null0R, 04.01.2012.

  1. null0R, 04.01.2012 #1
    null0R

    null0R Threadstarter App-Anbieter (kostenpfl.)

    Beiträge:
    38
    Erhaltene Danke:
    4
    Registriert seit:
    18.01.2011
    Hi,

    möchte sich jemand erbarmen und mir den verdammten InputFilter erklären? Ich bekomme es einfach nicht hin...

    Mein Ziel: Man soll Kommazahlen eingeben, die aber zwischen 1 und 100 liegen müssen. Wenn man etwas eingibt, das aus der Reihe fällt, soll allerdings auch nicht gleich der ganze EditText-Inhalt verworfen werden, sondern einfach nicht weiter aktualisiert.

    Mein Ansatz:
    Code:
             InputFilter maxvalue = new InputFilter() {
                 @Override
                 public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
                     try {
                         String input = source.toString();
                         if(Float.parseFloat(input) < 100) {
                             return null;
                         }
                         return "";
                     } catch (Exception e) {
                         return "";
                     }
                 }
             };
             eage.setFilters(new InputFilter[] { maxvalue } );
    Probleme mit diesem Code: Wenn man etwas nicht-vorgesehenes eingibt, löscht er gleich den ganzen Inhalt der EditText-View. Außerdem akzeptiert er keinen Punkt für Kommazahlen.

    Was ich mich wirklich herzlichst frage: Wenn return ""; bewirkt, dass der gesamte Inhalt des Textfelds gelöscht wird (und nicht etwa, dass einfach keine Zeichen mehr an das Textfeld weitergeleitet werden), warum bewirkt etwa return dest.toString(); einfach nicht, dass der (alte) Inhalt des Textfelds bestehen bleibt?! Stattdessen vermehren sich die bestehenden Zeichen plötzlich explosionsartig und das Programm stürzt ab.

    Bitte, bitte erklärt mir return im Zusammenhang mit einem InputFilter. :/
     
  2. Tom299, 04.01.2012 #2
    Tom299

    Tom299 Android-Experte

    Beiträge:
    602
    Erhaltene Danke:
    120
    Registriert seit:
    31.08.2011
    Am besten wirfst du mal den Debugger an und schaust dir an, was in den einzelnen Variablen steht.

    Wenn jemand eine Zahl eintippt, dann steht in source immer nur 1 Zeichen. Nur wenn man was ins Feld reinkopiert oder du das Feld vom Programmcode aus mit einer Zahl setzt, steht in source der ganze String. Das mußt du auch jeden Fall schon mal berücksichtigen.

    Dann ist natürlich noch wichtig, wieviele Zeichen schon in dest stehen, damit du weißt, an welcher Stelle der benutzer gerade seine eingabe macht.

    Also ganz so einfach wie if(Float.parseFloat(input) < 100) wirds dann wohl nicht ;-)

    Aber generell sollte mit return "" die Eingabe unterdrückt werden, also das eingegeben Zeichen bzw. der ganze String, falls kopiert oder zugewiesen wurde, mit return null wird die Eingabe soweit ich das noch weiß zugelassen.
     
  3. null0R, 04.01.2012 #3
    null0R

    null0R Threadstarter App-Anbieter (kostenpfl.)

    Beiträge:
    38
    Erhaltene Danke:
    4
    Registriert seit:
    18.01.2011
    Hi,

    danke für die Antwort. :)

    Auf die Idee bin ich auch schon gekommen, aber Log.d hat ergeben, dass in source sehr wohl der Inhalt des gesamten Textfelds steht. Zuvor versuchte ich es nämlich mit
    Code:
    String input = dest.toString() + source.toString();
    weil ich diese Zeile in etwa so auch als Beispiel im Internet gefunden hatte. Leider erfolglos, verursachte auch Fehler.

    Warum leert sich dann bei mir das gesamte Textfeld durch return "";? :/
     
  4. null0R, 04.01.2012 #4
    null0R

    null0R Threadstarter App-Anbieter (kostenpfl.)

    Beiträge:
    38
    Erhaltene Danke:
    4
    Registriert seit:
    18.01.2011
    So, Entschuldigung für den doppelten Beitrag, aber ich weiß jetzt, wodurch mein Problem verursacht ist und des Rätsels Lösung ist denkbar unbefriedigend und bietet keine Lösung für das eigentliche Problem... und zwar veralten sich schlicht und ergreifend die Tastaturen anders. Die normale (?) Android-Tastatur unter CM7 akzeptiert diese Lösung wie gewünscht:
    Code:
            InputFilter maxvalue = new InputFilter() {
                @Override
                public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
                    try {
                        String input = dest.toString() + source.toString();
                        if(Float.parseFloat(input) < 100) {
                            return source;
                        }
                        return "";
                    } catch (Exception e) {
                        return "";
                    }
                }
            };
            eage.setFilters(new InputFilter[] { new InputFilter.LengthFilter(5), maxvalue } );
    ... aber SwiftKey, die Tastatur, die ich eigentlich nutze, scheint damit nichts anfangen zu können.

    Außerdem finde ich, die Eingabe wirkt langsamer/verzögert und "laggt" irgendwie, wenn man so Filter anwendet.

    Gibt es ansonsten irgendwelche Alternativen, um mein Problem (für alle Tastaturen) zu lösen?
    Soll ichs mit einem onKeyListener probieren?

    Vielen Dank. :/
     
  5. null0R, 04.01.2012 #5
    null0R

    null0R Threadstarter App-Anbieter (kostenpfl.)

    Beiträge:
    38
    Erhaltene Danke:
    4
    Registriert seit:
    18.01.2011
    Tja, was soll ich sagen. Dritter Beitrag in Folge und das Thema hat sich endlich erledigt. :) Irgendwie funktioniert es doch mit SwiftKey. Ich glaube, man darf entweder nicht den InputFilter abstrakt so erstellen (falls sich das so nennt), sondern sollte lieber eine eigene Klasse dafür vorziehen. Oder man darf es nicht zu Exceptions kommen lassen. Aber ehrlich gesagt weiß ich nicht, ob irgendwas damit zu tun hat.

    Jedenfalls habe ich - glaube ich - nicht wirklich was anders gemacht und so funktioniert es mit beiden von mir getesteten Tastaturen:
    Code:
    package dein.package.name;
    
    import android.text.InputFilter;
    import android.text.Spanned;
    
    public class InputFilterMaximumValue implements InputFilter
    {
        private Integer max;
        
        
        public InputFilterMaximumValue(Integer max)
        {
            this.max = max;
        }
    
        public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend)
        {
            // Möchte löschen
            if(source.length() == 0) {
                return "";
            }
            
            // Ansonsten nur normale Eingabe von Zahlen und Kommas bitte
            if(source.length() == 1 && source.toString().matches("[0-9,.]"))
            {
                // Erstes Zeichen sogar nur eine Zahl
                if(dest.length() == 0 && Character.isDigit(source.charAt(0)))
                {
                    return null;
                }
                
                // Wenn noch kein Komma erhalten, dann darf das rein (deutsches wird umgewandelt)
                if(source.charAt(0) == ',' || source.charAt(0) == '.')
                {
                    if(!dest.toString().contains("."))
                    {
                        return ".";
                    }
                    return "";
                }
                
                // Eingabestring bauen
                String input = dest.subSequence(0, dstart).toString() + source.toString();
                if(dstart < dest.length())
                {
                    // Cursor ist irgendwo mittendrin
                    input += dest.subSequence(dstart, dest.length()).toString();
                }
                
                // Okay, letztlich gucken wir, ob das Ganze noch in die verlangte Größe passt
                if(Float.parseFloat(input) <= this.max)
                {
                    return null;
                }
            }
            return "";
        }
    }
    
    Code:
            eage.setFilters(new InputFilter[] { new InputFilter.LengthFilter(5), new InputFilterMaximumValue(100) });
    
    Funktioniert glaube ich ziemlich gut so.
     

Diese Seite empfehlen