Komma für Dezimaltrennzeichen (',') mit numberDecimal inputType in EditText

133

Das inputType numberDecimalin EditTextverwendet den Punkt '.' als Dezimaltrennzeichen. In Europa ist es üblich, stattdessen ein Komma zu verwenden. Obwohl mein Gebietsschema auf Deutsch eingestellt ist, ist das Dezimaltrennzeichen immer noch das '.'

Gibt es eine Möglichkeit, das Komma als Dezimaltrennzeichen zu erhalten?

mseo
quelle
1
Dieser Fehler wurde endlich in Android O behoben
Lovis
Sie sagen, es ist behoben, aber ich kann nicht bestätigen, dass es behoben ist? können Sie?
Sebastian
5
Ich kann bestätigen, dass es NICHT behoben ist, zumindest auf meinem Nexus 4 mit Android 8.1 (auch bekannt als LineageOS 15.1). Wenn Einstellungen-> Sprache auf Französisch (Frankreich) eingestellt ist, bietet ein EditText mit android: inputType = "numberDecimal" das Trennzeichen ',' (Komma), lehnt jedoch die Annahme des Kommas ab. Das angebotene '.' (Dezimalpunkt) wird akzeptiert. Es ist über 9 Jahre her, seit dieser Fehler erstmals gemeldet wurde. Ist das eine Art Rekord? Lame.
Peter

Antworten:

106

Eine Problemumgehung (bis Google diesen Fehler behoben hat) ist die Verwendung von EditTextwith android:inputType="numberDecimal"und android:digits="0123456789.,".

Fügen Sie dann dem EditText einen TextChangedListener mit dem folgenden afterTextChanged hinzu:

public void afterTextChanged(Editable s) {
    double doubleValue = 0;
    if (s != null) {
        try {
            doubleValue = Double.parseDouble(s.toString().replace(',', '.'));
        } catch (NumberFormatException e) {
            //Error
        }
    }
    //Do something with doubleValue
}
Martin
quelle
1
@Zoombie für das Komma (,) auf Ihrer Tastatur hängt von der auf Ihrem Gerät eingestellten Sprache ab. Wenn Ihre Eingabe den Typ numberDecimal hat und Ihre Sprache Englisch (USA) ist, wird sie auf Nexus-Geräten angezeigt (Referenz). Es ist möglich, dass Nicht-Nexus-Geräte dies nicht respektieren
hcpl
11
Es funktioniert, aber beachten Sie, dass ein Text wie "24,22.55" durchgelassen werden kann. Möglicherweise müssen Sie eine zusätzliche Validierung hinzufügen, um dies zu beheben!
Dimsuz
8
Ist das noch der richtige Weg?
Willi Mentzel
Verwenden Sie noch besser char localizedSeparator = DecimalFormatSymbols.getInstance (). GetDecimalSeparator (); localizedFloatString = localizedFloatString.replace ('.', localizedSeparator);
Southton
4
Scheint so, als würde man nur einen Fehler gegen einen anderen tauschen. Wie oben implementiert, funktioniert dies für Gebietsschemas, die anstelle von verwenden. auf Kosten der weltweit üblichen Umkehrung. Die Optimierung von @ southerton hilft dabei, aber Ihre Benutzer können überrascht sein, wenn sie eine treffen. und haben ein, erscheinen in der Eingabe.
Nick
30

Eine Variation der hier angebotenen "Digit" -Lösungen:

char separator = DecimalFormatSymbols.getInstance().getDecimalSeparator();
input.setKeyListener(DigitsKeyListener.getInstance("0123456789" + separator));

Berücksichtigung des Gebietsschema-Trennzeichens.

dstibbe
quelle
Dies ist die sauberste Antwort auf die ursprüngliche Frage. Danke
peter.bartos
Platziere dies in onCreate (), das ist der richtige Weg, IMHO.
TechNyquist
6
Ich mag das, aber seien Sie vorsichtig ... es gibt Tastaturen, denen das Gebietsschema des Benutzers egal ist, also Benutzer, die den Schlüssel nicht ,in ihren Tastaturen haben. Beispiele: Samsung-Tastatur (KitKat).
Brais Gabin
2
Dies ermöglicht doppelte Dezimaltrennzeichen. Siehe Antwort unten, um damit umzugehen
Esdras Lopez
19

Folgende Code-Währungsmaske für EditText ($ 123.125,155)

XML-Layout

  <EditText
    android:inputType="numberDecimal"
    android:layout_height="wrap_content"
    android:layout_width="200dp"
    android:digits="0123456789.,$" />

Code

EditText testFilter=...
testFilter.addTextChangedListener( new TextWatcher() {
        boolean isEdiging;
        @Override public void onTextChanged(CharSequence s, int start, int before, int count) { }
        @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { }

        @Override public void afterTextChanged(Editable s) {
            if(isEdiging) return;
            isEdiging = true;

            String str = s.toString().replaceAll( "[^\\d]", "" );
            double s1 = Double.parseDouble(str);

            NumberFormat nf2 = NumberFormat.getInstance(Locale.ENGLISH);
            ((DecimalFormat)nf2).applyPattern("$ ###,###.###");
            s.replace(0, s.length(), nf2.format(s1));

            isEdiging = false;
        }
    });
user1269737
quelle
16

Dies ist ein bekannter Fehler im Android SDK. Die einzige Problemumgehung besteht darin, eine eigene Softtastatur zu erstellen. Ein Beispiel für die Implementierung finden Sie hier .

EricLarch
quelle
15
Gibt es nach vier Jahren Neuigkeiten?
Antonio Sesto
Erleben Sie dies auch in Xamarin.Forms. Die Kultur ist {se-SV} und das Nummernfeld zeigt bot "," (Dezimaltrennzeichen) und "." (Tausender Gruppentrennzeichen) aber beim Drücken des "," wird nichts in das Textfeld eingegeben und kein Ereignis wird
ausgelöst
Ich kann bestätigen, dass der Fehler weiterhin besteht.
Lensflare
behoben in Android O Entwickler Vorschau
R00We
6

Martins Antwort funktioniert nicht, wenn Sie den EditText programmgesteuert instanziieren. Ich habe die eingeschlossene DigitsKeyListenerKlasse von API 14 geändert , um sowohl Komma als auch Punkt als Dezimaltrennzeichen zu berücksichtigen.

Rufen Sie dazu setKeyListener()die EditTextz

// Don't allow for signed input (minus), but allow for decimal points
editText.setKeyListener( new MyDigitsKeyListener( false, true ) );

Sie müssen jedoch immer noch Martins Trick verwenden TextChangedListener, um Kommas durch Punkte zu ersetzen

import android.text.InputType;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.method.NumberKeyListener;
import android.view.KeyEvent;

class MyDigitsKeyListener extends NumberKeyListener {

    /**
     * The characters that are used.
     *
     * @see KeyEvent#getMatch
     * @see #getAcceptedChars
     */
    private static final char[][] CHARACTERS = new char[][] {
        new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' },
        new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-' },
        new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', ',' },
        new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '.', ',' },
    };

    private char[] mAccepted;
    private boolean mSign;
    private boolean mDecimal;

    private static final int SIGN = 1;
    private static final int DECIMAL = 2;

    private static MyDigitsKeyListener[] sInstance = new MyDigitsKeyListener[4];

    @Override
    protected char[] getAcceptedChars() {
        return mAccepted;
    }

    /**
     * Allocates a DigitsKeyListener that accepts the digits 0 through 9.
     */
    public MyDigitsKeyListener() {
        this(false, false);
    }

    /**
     * Allocates a DigitsKeyListener that accepts the digits 0 through 9,
     * plus the minus sign (only at the beginning) and/or decimal point
     * (only one per field) if specified.
     */
    public MyDigitsKeyListener(boolean sign, boolean decimal) {
        mSign = sign;
        mDecimal = decimal;

        int kind = (sign ? SIGN : 0) | (decimal ? DECIMAL : 0);
        mAccepted = CHARACTERS[kind];
    }

    /**
     * Returns a DigitsKeyListener that accepts the digits 0 through 9.
     */
    public static MyDigitsKeyListener getInstance() {
        return getInstance(false, false);
    }

    /**
     * Returns a DigitsKeyListener that accepts the digits 0 through 9,
     * plus the minus sign (only at the beginning) and/or decimal point
     * (only one per field) if specified.
     */
    public static MyDigitsKeyListener getInstance(boolean sign, boolean decimal) {
        int kind = (sign ? SIGN : 0) | (decimal ? DECIMAL : 0);

        if (sInstance[kind] != null)
            return sInstance[kind];

        sInstance[kind] = new MyDigitsKeyListener(sign, decimal);
        return sInstance[kind];
    }

    /**
     * Returns a DigitsKeyListener that accepts only the characters
     * that appear in the specified String.  Note that not all characters
     * may be available on every keyboard.
     */
    public static MyDigitsKeyListener getInstance(String accepted) {
        // TODO: do we need a cache of these to avoid allocating?

        MyDigitsKeyListener dim = new MyDigitsKeyListener();

        dim.mAccepted = new char[accepted.length()];
        accepted.getChars(0, accepted.length(), dim.mAccepted, 0);

        return dim;
    }

    public int getInputType() {
        int contentType = InputType.TYPE_CLASS_NUMBER;
        if (mSign) {
            contentType |= InputType.TYPE_NUMBER_FLAG_SIGNED;
        }
        if (mDecimal) {
            contentType |= InputType.TYPE_NUMBER_FLAG_DECIMAL;
        }
        return contentType;
    }

    @Override
    public CharSequence filter(CharSequence source, int start, int end,
                               Spanned dest, int dstart, int dend) {
        CharSequence out = super.filter(source, start, end, dest, dstart, dend);

        if (mSign == false && mDecimal == false) {
            return out;
        }

        if (out != null) {
            source = out;
            start = 0;
            end = out.length();
        }

        int sign = -1;
        int decimal = -1;
        int dlen = dest.length();

        /*
         * Find out if the existing text has '-' or '.' characters.
         */

        for (int i = 0; i < dstart; i++) {
            char c = dest.charAt(i);

            if (c == '-') {
                sign = i;
            } else if (c == '.' || c == ',') {
                decimal = i;
            }
        }
        for (int i = dend; i < dlen; i++) {
            char c = dest.charAt(i);

            if (c == '-') {
                return "";    // Nothing can be inserted in front of a '-'.
            } else if (c == '.' ||  c == ',') {
                decimal = i;
            }
        }

        /*
         * If it does, we must strip them out from the source.
         * In addition, '-' must be the very first character,
         * and nothing can be inserted before an existing '-'.
         * Go in reverse order so the offsets are stable.
         */

        SpannableStringBuilder stripped = null;

        for (int i = end - 1; i >= start; i--) {
            char c = source.charAt(i);
            boolean strip = false;

            if (c == '-') {
                if (i != start || dstart != 0) {
                    strip = true;
                } else if (sign >= 0) {
                    strip = true;
                } else {
                    sign = i;
                }
            } else if (c == '.' || c == ',') {
                if (decimal >= 0) {
                    strip = true;
                } else {
                    decimal = i;
                }
            }

            if (strip) {
                if (end == start + 1) {
                    return "";  // Only one character, and it was stripped.
                }

                if (stripped == null) {
                    stripped = new SpannableStringBuilder(source, start, end);
                }

                stripped.delete(i - start, i + 1 - start);
            }
        }

        if (stripped != null) {
            return stripped;
        } else if (out != null) {
            return out;
        } else {
            return null;
        }
    }
}
JesperB
quelle
from doc: KeyListener sollte nur in Fällen verwendet werden, in denen eine Anwendung über eine eigene Bildschirmtastatur verfügt und auch Tastaturereignisse entsprechend verarbeiten möchte. developer.android.com/reference/android/text/method/…
Loda
6

Sie können Folgendes für verschiedene Gebietsschemas verwenden

private void localeDecimalInput(final EditText editText){

    DecimalFormat decFormat = (DecimalFormat) DecimalFormat.getInstance(Locale.getDefault());
    DecimalFormatSymbols symbols=decFormat.getDecimalFormatSymbols();
    final String defaultSeperator=Character.toString(symbols.getDecimalSeparator());

    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 editable) {
            if(editable.toString().contains(defaultSeperator))
                editText.setKeyListener(DigitsKeyListener.getInstance("0123456789"));
            else
                editText.setKeyListener(DigitsKeyListener.getInstance("0123456789" + defaultSeperator));
        }
    });
}
Ismail
quelle
Dies ist die beste Lösung für mich, aber es gibt Probleme mit einigen Handys, z. B. Samsung, bei denen das Koma "," auf der Tastatur nicht angezeigt wird. Also habe ich dies geändert, um sowohl Koma als auch Punkt zuzulassen, aber dann entsprechend dem Gebietsschema ersetzt
Riccardo Casatta
5

Sie können die folgende Problemumgehung verwenden, um auch Komma als gültige Eingabe einzufügen: -

Durch XML:

<EditText
    android:inputType="number"
    android:digits="0123456789.," />

Programmatisch:

EditText input = new EditText(THE_CONTEXT);
input.setKeyListener(DigitsKeyListener.getInstance("0123456789.,"));

Auf diese Weise zeigt das Android-System die Tastatur der Zahlen an und ermöglicht die Eingabe von Kommas. Hoffe das beantwortet die Frage :)

MiaN KhaLiD
quelle
Mit dieser Lösung, wenn Sie auf "," tippen, aber der Bearbeitungstext "anzeigt".
Mara Jimenez
2

Für Mono (Droid) -Lösungen:

decimal decimalValue = decimal.Parse(input.Text.Replace(",", ".") , CultureInfo.InvariantCulture);
Ludwo
quelle
1

Sie können Folgendes tun:

DecimalFormatSymbols d = DecimalFormatSymbols.getInstance(Locale.getDefault());
input.setFilters(new InputFilter[] { new DecimalDigitsInputFilter(5, 2) });
input.setKeyListener(DigitsKeyListener.getInstance("0123456789" + d.getDecimalSeparator()));

Und dann könnten Sie einen Eingabefilter verwenden:

    public class DecimalDigitsInputFilter implements InputFilter {

Pattern mPattern;

public DecimalDigitsInputFilter(int digitsBeforeZero, int digitsAfterZero) {
    DecimalFormatSymbols d = new DecimalFormatSymbols(Locale.getDefault());
    String s = "\\" + d.getDecimalSeparator();
    mPattern = Pattern.compile("[0-9]{0," + (digitsBeforeZero - 1) + "}+((" + s + "[0-9]{0," + (digitsAfterZero - 1) + "})?)||(" + s + ")?");
}

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

    Matcher matcher = mPattern.matcher(dest);
    if (!matcher.matches())
        return "";
    return null;
}

}}

Pablo
quelle
Es könnte einen Abstand zwischen tausend und hundert geben, dieses Muster würde die formatierte Eingabe ablehnen
Eric Zhao
1

IMHO ist der beste Ansatz für dieses Problem, nur den InputFilter zu verwenden. Ein netter Kern ist hier DecimalDigitsInputFilter . Dann können Sie einfach:

editText.setInputType(TYPE_NUMBER_FLAG_DECIMAL | TYPE_NUMBER_FLAG_SIGNED | TYPE_CLASS_NUMBER)
editText.setKeyListener(DigitsKeyListener.getInstance("0123456789,.-"))
editText.setFilters(new InputFilter[] {new DecimalDigitsInputFilter(5,2)});
Arkadiusz Cieśliński
quelle
Es hat wie ein Zauber funktioniert, danke! (nach so vielen falschen Lösungen oben ... :() Aber ich habe eine Frage: Wie kann ich dieses Komma (",") erreichen, das auf dem Bildschirm angezeigt wird, nicht Punkt ("."), weil wir in Ungarn Komma als Dezimaltrennzeichen verwenden .
Abigail La'Fay
1
android: digits = "0123456789", Einstellung kann zum EditText hinzugefügt werden. Darüber hinaus kann anstelle null in dem DecimalDigitsInputFilter zurückzukehren, können Sie source.replace zurückgeben ( „‚ ‘.“) Nach der Antwort stackoverflow.com/a/40020731/1510222 gibt es keine Möglichkeit zu verstecken Punkt in einer Standard - Tastatur
Arkadiusz Cieśliński
1

Um Ihre Eingabe zu lokalisieren, verwenden Sie:

char sep = DecimalFormatSymbols.getInstance().getDecimalSeparator();

und dann hinzufügen:

textEdit.setKeyListener(DigitsKeyListener.getInstance("0123456789" + sep));

dann vergessen Sie nicht, "," durch "zu ersetzen." Float oder Double können es also fehlerfrei analysieren.

Milos Simic Simo
quelle
1
Diese Lösung ermöglicht die Eingabe mehrerer Kommas
Leo Droidcoder
1

Alle anderen Beiträge hier hatten große Löcher, daher hier eine Lösung, die:

  • Wenn Sie Kommas oder Punkte basierend auf der Region erzwingen, können Sie nicht das Gegenteil eingeben.
  • Wenn der EditText mit einem bestimmten Wert beginnt, ersetzt er bei Bedarf das richtige Trennzeichen.

In der XML:

<EditText
    ...
    android:inputType="numberDecimal" 
    ... />

Klassenvariable:

private boolean isDecimalSeparatorComma = false;

Suchen Sie in onCreate das Trennzeichen, das im aktuellen Gebietsschema verwendet wird:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    NumberFormat nf = NumberFormat.getInstance();
    if (nf instanceof DecimalFormat) {
        DecimalFormatSymbols sym = ((DecimalFormat) nf).getDecimalFormatSymbols();
        char decSeparator = sym.getDecimalSeparator();
        isDecimalSeparatorComma = Character.toString(decSeparator).equals(",");
    }
}

Verwenden Sie dies auch onCreate, um es zu aktualisieren, wenn Sie einen aktuellen Wert laden:

// Replace editText with commas or periods as needed for viewing
String editTextValue = getEditTextValue(); // load your current value
if (editTextValue.contains(".") && isDecimalSeparatorComma) {
    editTextValue = editTextValue.replaceAll("\\.",",");
} else if (editTextValue.contains(",") && !isDecimalSeparatorComma) {
    editTextValue = editTextValue.replaceAll(",",".");
}
setEditTextValue(editTextValue); // override your current value

Fügen Sie auch onCreate die Listener hinzu

editText.addTextChangedListener(editTextWatcher);

if (isDecimalSeparatorComma) {
    editText.setKeyListener(DigitsKeyListener.getInstance("0123456789,"));
} else {
    editText.setKeyListener(DigitsKeyListener.getInstance("0123456789."));
}

editTextWatcher

TextWatcher editTextWatcher = 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) {
        String editTextValue = s.toString();

        // Count up the number of commas and periods
        Pattern pattern = Pattern.compile("[,.]");
        Matcher matcher = pattern.matcher(editTextValue);
        int count = 0;
        while (matcher.find()) {
            count++;
        }

        // Don't let it put more than one comma or period
        if (count > 1) {
            s.delete(s.length()-1, s.length());
        } else {
            // If there is a comma or period at the end the value hasn't changed so don't update
            if (!editTextValue.endsWith(",") && !editTextValue.endsWith(".")) {
                doSomething()
            }
        }
    }
};

Beispiel doSomething (): Konvertieren Sie zur Datenmanipulation in den Standardzeitraum

private void doSomething() {
    try {
        String editTextStr = editText.getText().toString();
        if (isDecimalSeparatorComma) {
            editTextStr = editTextStr.replaceAll(",",".");
        }
        float editTextFloatValue = editTextStr.isEmpty() ?
                0.0f :
                Float.valueOf(editTextStr);

        ... use editTextFloatValue
    } catch (NumberFormatException e) {
        Log.e(TAG, "Error converting String to Double");
    }
}
Elijah Fry
quelle
0

Android hat einen eingebauten Zahlenformatierer.

Sie können dies zu Ihrem hinzufügen EditText, um Dezimalstellen und Kommas zuzulassen: android:inputType="numberDecimal"undandroid:digits="0123456789.,"

Dann irgendwo in Ihrem Code, entweder wenn der Benutzer auf Speichern klickt oder nachdem Text eingegeben wurde (verwenden Sie einen Listener).

// Format the number to the appropriate double
try { 
    Number formatted = NumberFormat.getInstance().parse(editText.getText().toString());
    cost = formatted.doubleValue();
} catch (ParseException e) {
    System.out.println("Error parsing cost string " + editText.getText().toString());
    cost = 0.0;
}
Luis
quelle
0

Ich habe beschlossen, das Komma nur während der Bearbeitung in Punkt zu ändern. Hier ist meine knifflige und relativ einfache Problemumgehung:

    editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            EditText editText = (EditText) v; 
            String text = editText.getText().toString();
            if (hasFocus) {
                editText.setText(text.replace(",", "."));
            } else {
                if (!text.isEmpty()) {
                    Double doubleValue = Double.valueOf(text.replace(",", "."));
                    editText.setText(someDecimalFormatter.format(doubleValue));
                }
            }
        }
    });

someDecimalFormatter verwendet Komma oder Punkt, abhängig vom Gebietsschema

KaMyLL
quelle
0

Ich weiß nicht, warum Ihre Antworten so kompliziert sind. Wenn es einen Fehler im SDK gibt, müssen Sie ihn überschreiben oder umgehen.

Ich habe den zweiten Weg gewählt, um dieses Problem zu lösen. Wenn Sie Ihre Zeichenfolge als formatieren Locale.ENGLISHund dann in die EditTextZeichenfolge (auch als leere Zeichenfolge) einfügen. Beispiel:

String.format(Locale.ENGLISH,"%.6f", yourFloatNumber);

Wenn Sie dieser Lösung nachjagen, ist Ihr Ergebnis mit der angezeigten Tastatur kompatibel. Dann arbeiten Gleitkomma- und Doppelnummern in der für Programmiersprachen typischen Weise mit Punkt anstelle von Komma.

Dominik
quelle
0

Meine Lösung ist:

  • In der Haupttätigkeit:

    char separator =DecimalFormatSymbols.getInstance().getDecimalSeparator(); textViewPitchDeadZone.setKeyListener(DigitsKeyListener.getInstance("0123456789" + separator));

  • In der XML-Datei: android:imeOptions="flagNoFullscreen" android:inputType="numberDecimal"

und ich habe das Double im editText als String genommen.

Lseb
quelle
0

Ich kann bestätigen, dass die vorgeschlagenen Korrekturen nicht auf Samsung IMEs (zumindest auf S6 und S9) und möglicherweise auf LG funktionieren. Sie zeigen immer noch einen Punkt als Dezimaltrennzeichen, unabhängig vom Gebietsschema. Der Wechsel zu Googles IME behebt dieses Problem, ist jedoch für die meisten Entwickler kaum eine Option.

Es wurde auch nicht in Oreo für diese Tastaturen behoben, da es eine Korrektur ist, die Samsung und / oder LG vornehmen müssen, um dann sogar auf ihre alten Handys zu pushen.

Ich habe stattdessen das Ziffern -Tastatur-Projekt gegabelt und einen Modus hinzugefügt, in dem es sich wie eine IME: Gabel verhält . Einzelheiten finden Sie im Projektbeispiel. Dies hat für mich ganz gut funktioniert und ähnelt vielen der gefälschten IMEs mit "PIN-Eingabe", die Sie in Banking-Apps sehen.

Beispiel-App-Screenshot

Kevin Read
quelle
0

Es ist mehr als 8 Jahre vergangen und ich bin überrascht, dass dieses Problem noch nicht behoben ist ...
Ich hatte mit diesem einfachen Problem zu kämpfen, da die am besten bewertete Antwort von @Martin die Eingabe mehrerer Trennzeichen ermöglicht, dh der Benutzer kann "12 ,," eingeben. ,,, 12,1 ,, 21,2, "
Außerdem besteht das zweite Problem darin, dass bei einigen Geräten das Komma auf der numerischen Tastatur nicht angezeigt wird (oder das mehrfache Drücken einer Punkttaste erforderlich ist).

Hier ist meine Problemumgehungslösung, die die genannten Probleme löst und es dem Benutzer ermöglicht, "einzugeben". und ',', aber in EditText wird das einzige Dezimaltrennzeichen angezeigt, das dem aktuellen Gebietsschema entspricht:

editText.apply { addTextChangedListener(DoubleTextChangedListener(this)) }

Und der Textbeobachter:

  open class DoubleTextChangedListener(private val et: EditText) : TextWatcher {

    init {
        et.inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL
        et.keyListener = DigitsKeyListener.getInstance("0123456789.,")
    }

    private val separator = DecimalFormatSymbols.getInstance().decimalSeparator

    override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
        //empty
    }

    @CallSuper
    override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
        et.run {
            removeTextChangedListener(this@DoubleTextChangedListener)
            val formatted = toLocalizedDecimal(s.toString(), separator)
            setText(formatted)
            setSelection(formatted.length)
            addTextChangedListener(this@DoubleTextChangedListener)
        }
    }

    override fun afterTextChanged(s: Editable?) {
        // empty
    }

    /**
     * Formats input to a decimal. Leaves the only separator (or none), which matches [separator].
     * Examples:
     * 1. [s]="12.12", [separator]=',' -> result= "12,12"
     * 2. [s]="12.12", [separator]='.' -> result= "12.12"
     * 4. [s]="12,12", [separator]='.' -> result= "12.12"
     * 5. [s]="12,12,,..,,,,,34..,", [separator]=',' -> result= "12,1234"
     * 6. [s]="12.12,,..,,,,,34..,", [separator]='.' -> result= "12.1234"
     * 7. [s]="5" -> result= "5"
     */
    private fun toLocalizedDecimal(s: String, separator: Char): String {
        val cleared = s.replace(",", ".")
        val splitted = cleared.split('.').filter { it.isNotBlank() }
        return when (splitted.size) {
            0 -> s
            1 -> cleared.replace('.', separator).replaceAfter(separator, "")
            2 -> splitted.joinToString(separator.toString())
            else -> splitted[0]
                    .plus(separator)
                    .plus(splitted.subList(1, splitted.size - 1).joinToString(""))
        }
    }
}
Leo Droidcoder
quelle
0

Einfache Lösung, machen Sie ein benutzerdefiniertes Steuerelement. (Dies ist in Xamarin Android gemacht, sollte aber leicht auf Java portieren)

public class EditTextDecimalNumber:EditText
{
    readonly string _numberFormatDecimalSeparator;

    public EditTextDecimalNumber(Context context, IAttributeSet attrs) : base(context, attrs)
    {
        InputType = InputTypes.NumberFlagDecimal;
        TextChanged += EditTextDecimalNumber_TextChanged;
        _numberFormatDecimalSeparator = System.Threading.Thread.CurrentThread.CurrentUICulture.NumberFormat.NumberDecimalSeparator;

        KeyListener = DigitsKeyListener.GetInstance($"0123456789{_numberFormatDecimalSeparator}");
    }

    private void EditTextDecimalNumber_TextChanged(object sender, TextChangedEventArgs e)
    {
        int noOfOccurence = this.Text.Count(x => x.ToString() == _numberFormatDecimalSeparator);
        if (noOfOccurence >=2)
        {
            int lastIndexOf = this.Text.LastIndexOf(_numberFormatDecimalSeparator,StringComparison.CurrentCulture);
            if (lastIndexOf!=-1)
            {
                this.Text = this.Text.Substring(0, lastIndexOf);
                this.SetSelection(this.Text.Length);
            }

        }
    }
}
Nicolai
quelle
0

Sie könnten verwenden inputType="phone", aber in diesem Fall müssten Sie sich mit mehreren befassen ,oder .anwesend sein, so dass eine zusätzliche Validierung erforderlich wäre.

Jacks Medulla oblongata
quelle
-1

Ich denke, diese Lösung ist weniger komplex als die anderen hier geschriebenen:

<EditText
    android:inputType="numberDecimal"
    android:digits="0123456789," />

Auf diese Weise, wenn Sie das '.' Drücken. in der Softtastatur passiert nichts; Es sind nur Zahlen und Kommas zulässig.

Jorge Alcolea Coronel
quelle
4
Wenn Sie dies tun, brechen Sie einfach alle Gebietsschemas auf, die '.' verwenden. stattdessen.
Nick