Android numerisches Eingabefeld

In diesem Artikel möchte ich das Problem der Benutzereingabe von Zahlen mit einer bestimmten Genauigkeit hervorheben.
Mal sehen, was im Arsenal von Android ist und dieses Problem lösen.

Beginnen wir mit den Anforderungen.


Grundvoraussetzungen:
  • Implementieren Sie ein Eingabefeld, in das Sie nur Zahlen mit einer bestimmten Genauigkeit eingeben können.
  • Die Genauigkeit wird durch die Anzahl der signifikanten Stellen vor und nach dem Dezimalpunkt angegeben.

Zusätzliche Anforderungen:
  • Eingabe-Cursor-Unterstützung.
  • Standard-Bearbeitungsoptionen: Kopieren, Ausschneiden und Einfügen.

Analyse


Von der gesamten Palette der Steuerelemente Androidinteressieren wir uns für das Widget EditText.
Wir wenden uns der Dokumentation zu und sehen, was das Android SDK uns bietet.

EditTextgeerbt von TextView, das wiederum die folgenden Eigenschaften aufweist:
XML-Markup
digits - Mit dieser Option können Sie eine Reihe von Sonderzeichen festlegen, die das Feld annehmen kann, und den Zahleneingabemodus automatisch aktivieren.
numeric- Definiert einen Handler für die Zahleneingabe.
inputType- Wenn Sie einen Satz konstanter Werte verwenden, können Sie den gewünschten Eingabehandler generieren.

Öffentliche Methoden der Klasse
setFilters - Hier können Sie eine Reihe von Filtern angeben, die bei der Eingabe von Werten in das Feld angewendet werden.

digits, numericundinputTypeSie können die Anzahl der eingegebenen Zeichen einschränken, haben aber keinen Einfluss auf die Genauigkeit der Zahl, aber setFiltersgenau das brauchen wir.

Implementierung


Bevor Sie Ihren eigenen Filter erstellen, werden wir ihn so einrichten, dass nur Zahlen und das Dezimaltrennzeichen in das Feld eingegeben werden können.
numberEditText.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);

Jetzt setzen wir einen eigenen Filter für das Eingabefeld, um nur Werte zu akzeptieren, die der angegebenen Genauigkeit entsprechen.
Wir müssen die Schnittstelle implementieren InputFilterund die Methode neu definieren filter.

Laut Dokumentation wird diese Methode aufgerufen, wenn der Wert im Eingabefeld (dest) im Bereich von dstart bis dend durch Text aus dem Puffer (source) im Bereich von start bis end ersetzt wird.
Beispiel für das Verständnis der obigen
Das Eingabefeld enthält 123456 (dest), der Cursor befindet sich auf 1 [23] 456 (dstart = 1, dend = 3), der Wert 789 wird aus dem Puffer eingefügt (source = 789, start = 0, end 3).

Die Methode gibt ein Klassenobjekt zurück CharSequence, das anstelle des aktuellen Werts im Eingabefeld gesetzt wird. Wenn der Wert des Eingabefelds nicht ersetzt werden muss, sollte er in der Methode zurückgegeben werden null.

Wir übergeben die Anzahl der Zeichen vor und nach dem Dezimaltrennzeichen an den Konstruktor unseres Filters.
Filterkonstruktor
public NumberInputFilter(int digsBeforeDot, int digsAfterDot) {
    this.digsBeforeDot = digsBeforeDot;
    this.digsAfterDot = digsAfterDot;
}


Definieren Sie die Methode neu filter. Der Algorithmus zur Überprüfung der Eingabewerte lautet wie folgt:
  1. Bevor Sie den Pufferwert in das Eingabefeld einfügen, fügen Sie diesen Wert in eine Variable ein.
  2. Wenn der erhaltene Wert unseren Genauigkeitsanforderungen entspricht, ermöglichen wir die Eingabe durch Rücksendung null.
  3. Andernfalls geben wir eine leere Zeichenfolge zurück, wodurch der Eingabewert aufgegeben wird.

Wir bilden den zukünftigen Wert nach der Benutzereingabe:
Zur Vereinfachung der Bearbeitung der Zeichenfolge erstellen Sie eine Instanz der Klasse StringBuilderauf der Grundlage des Anfangswerts des Eingabefelds und nehmen die erforderlichen Ersetzungen unter Berücksichtigung des Eingabewerts vor.
StringBuilder newText = new StringBuilder(dest).replace(dstart, dend, source.toString());

Als Ergebnis wird die Variable newTextwird den zukünftigen Wert eines Textfeldes enthalten.

Jetzt sollten wir die Richtigkeit des neuen Wertes überprüfen.
Es muss folgende Bedingungen erfüllen:
  1. Die Anzahl der Dezimaltrennzeichen sollte 1 nicht überschreiten.
    123, 123.45 - wahr, 12.3.4 - falsch.
  2. Die Anzahl der Zeichen des ganzzahligen und des gebrochenen Teils der Zahl muss der angegebenen Genauigkeit entsprechen.

Lassen Sie uns die Anzahl der Begrenzer überprüfen. Dazu werden wir alle Zeichen der resultierenden Zeichenfolge durchlaufen.
Wenn es ein Dezimaltrennzeichen gibt, merken Sie sich den Index. Wenn das Trennzeichen erneut gefunden wird, wird die Eingabe als falsch angesehen und der Zyklus wird gestoppt.
Suche nach Dezimaltrennzeichen
int size = newText.length();
int decInd = -1; // индекс десятичного разделителя
// проверяем десятичный разделитель
// количество разделителей не должно превышать 1
for (int i = 0; i < size; i++) {
    if (newText.charAt(i) == '.') {
        if (decInd < 0) {
            decInd = i; // запоминаем индекс разделителя
        } else { // разделителей более 1, некорректный ввод
            isValid = false;
            break;
        }
    }
}


Überprüfen Sie die Richtigkeit der Nummer. Wir kennen den Dezimaltrennungsindex bereits oder er fehlt.
Es bleibt nur die Länge der ganzen Zahl relativ zum Index des Trennzeichens zu vergleichen.
Überprüfung der Richtigkeit einer Zahl
if (decInd < 0) { // случай когда разделителя нет
    if (size > integerSize) { // проверяем длину всего числа
        isValid = false;
    }
} else if (decInd > digsBeforeDot) {// проверяем длину целой части
    isValid = false;
} else if (size - decInd - 1 > digsAfterDot) { // проверяем длину дробной части
    isValid = false;
}


Am Ende geben wir das Ergebnis zurück.
Wenn die Eingabe korrekt ist, geben wir zurück nullund akzeptieren damit die Eingabewerte.
Andernfalls geben wir eine leere Zeichenfolge zurück, um keine Werte an das Eingabefeld zu senden.
if (isValid) {
    return null;
} else {
    return "";
}

Vollständiger Quellcode @ github

Debuggen


Wir starten das Projekt und stellen unseren Testfall vor, wobei wir versuchen, über seine Grenzen hinauszugehen.
Als Testbeispiel verwenden wir die Nummer 123.45. Sie können keine Zahlen eingeben, die größer als 999,99 und kleiner als 0,01 sind.
Video


Wir sehen, dass die Anwendung die ganzzahligen und gebrochenen Teile der Zahl korrekt verarbeitet und die Einführung mehrerer Dezimaltrennzeichen verbietet.
Eine interessante Situation wird jedoch beobachtet, wenn wir das Dezimaltrennzeichen entfernen, dann gehen wir über die Grenzen der Genauigkeit hinaus.

Dies wird in der Dokumentation erwähnt.
Achten Sie darauf, keine Ersetzungen der Länge 0 abzulehnen, da dies passiert, wenn Sie Text löschen.

Sie müssen vorsichtig mit Ersetzungen der Länge Null sein, wie dies beim Löschen von Text der Fall ist.
Was ist wirklich passiert?

Unser Algorithmus funktionierte ordnungsgemäß und unter der Bedingung, dass die Länge des ganzzahligen Teils der Zahl überprüft wurde, ergab sich, dass die zulässige Genauigkeit verletzt wurde, und es wurde eine leere Zeichenfolge zurückgegeben. Die Aktion zum Löschen von Zeichen selbst wurde jedoch auf den ursprünglichen Wert des Eingabefelds angewendet.

Wir werden dieses Problem wie folgt lösen - wir werden die Tatsache der Entfernung von Zeichen aufdecken. Die Dokumentation schlägt vor, dass in diesem Fall eine Ersetzung der Länge Null erfolgt. Wir wählen die gelöschten Zeichen aus dem Anfangswert des Eingabefelds aus und geben sie als Ergebnis unserer Methode zurück, wodurch wir das Löschen ablehnen.
Wir müssen den Codeblock ändern, in dem das Ergebnis zurückgegeben wird
Zeichenlöschverarbeitung
if (isValid) {
    return null;
} else if (source.equals("")) { // обрабатываем удаление
    return dest.subSequence(dstart, dend); // возвращаем удаленные символы
} else {
    return "";
}


Wir starten das Projekt und prüfen.
Video


Damit ist der Testfall abgeschlossen, die gewünschte Genauigkeit wird erreicht.

Die Bibliothek wird erfolgreich in der Produktion eingesetzt.
Sie können es mit Gradle verbinden
repositories {
        maven { url "https://raw.githubusercontent.com/hyperax/Android-NumberEditText/master/maven-repo" }
}
compile 'ru.softbalance.widgets:NumberEditText:1.1.2'


Vollständiger Projektquellcode @ github .

Bonus


Es ist häufig erforderlich, die Anzeige der Systemtastatur für ein Eingabefeld zu deaktivieren.
Zum Beispiel, wenn Sie eine Tastatur aus einer Anwendung verwenden.

Die EditText-Klassenmethode, die in Android-Version 21 und höher
aufgetaucht ist, hilft : setShowSoftInputOnFocus (boolean show)

Eigentlich war diese Methode auch in früheren Versionen, aber privat.
Fügen Sie unsere Methode für das Eingabefeld showSoftInputOnFocusCompat hinzu
public void showSoftInputOnFocusCompat (boolean isShow) {
        showSoftInputOnFocus = isShow;
        if (Build.VERSION.SDK_INT >= 21) {
            setShowSoftInputOnFocus(showSoftInputOnFocus);
        } else {
            try {
                final Method method = EditText.class.getMethod("setShowSoftInputOnFocus", boolean.class);
                method.setAccessible(true);
                method.invoke(this, showSoftInputOnFocus);
            } catch (Exception e) {
                // ignore
            }
        }
    }


Ja, dies ist ein "Hack", aber dies ist der einfachste und kürzeste Weg, die Systemtastatur für das Eingabefeld auszublenden.

Jetzt auch beliebt: