webentwicklung-frage-antwort-db.com.de

Dezimaltrennzeichen (',') mit numberDecimal-Eingabe Geben Sie EditText ein

inputTypenumberDecimal in EditText verwendet den Punkt '.' als Dezimaltrennzeichen. In Europa ist es üblich, stattdessen ein Komma ',' zu verwenden. Obwohl mein Gebietsschema als deutsch eingestellt ist, ist das Dezimaltrennzeichen immer noch das '.

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

103
mseo

Eine Problemumgehung (bis Google diesen Fehler behoben hat) besteht in der Verwendung einer EditText mit Android:inputType="numberDecimal" und Android:digits="0123456789.,"

Fügen Sie dem EditText anschließend 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
}
91
Martin

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

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

Berücksichtigen Sie das Gebietsschema-Trennzeichen.

25
dstibbe

Folgender 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;
        }
    });
17
user1269737

Dies ist ein bekannter Fehler im Android SDK ..__ Die einzige Problemumgehung besteht darin, eine eigene Soft-Tastatur zu erstellen. Ein Implementierungsbeispiel finden Sie hier .

15
EricLarch

Die Antwort von Martins funktioniert nicht, wenn Sie den EditText programmgesteuert instanziieren. Ich ging weiter und modifizierte die eingeschlossene DigitsKeyListener-Klasse von API 14, um sowohl Komma als auch Punkt als Dezimaltrennzeichen zu berücksichtigen.

Um dies zu verwenden, rufen Sie setKeyListener() für die EditText auf, z.

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

Sie müssen jedoch immer noch Martin's Trick in der TextChangedListener verwenden, wo Sie die Kommas durch Punkte 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;
        }
    }
}
6
JesperB

Sie können die folgende Problemumgehung verwenden, um auch ein 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 Nummern an und ermöglicht die Eingabe von Kommas. Hoffe das beantwortet die Frage :)

5
MiaN KhaLiD

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

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

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

Sie könnten 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;
}

}

1
Pablo

um Ihre Eingabe zu lokalisieren, verwenden Sie:

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

und dann hinzufügen:

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

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

1

Meine Lösung ist:

  • In der Haupttätigkeit:

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

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

und ich nahm das Double im editText als String.

0
Lseb

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

Es wurde auch in Oreo für diese Tastaturen nicht repariert, da Samsung und/oder LG ein Fix haben, das dann zu ihren alten Mobilteilen zu drücken ist.

Ich habe stattdessen das number-keyboard-Projekt gegabelt und einen Modus hinzugefügt, in dem es sich wie ein IME verhält: fork . Details finden Sie im Projektbeispiel. Dies hat für mich ziemlich gut funktioniert und ähnelt vielen gefälschten IMEs der "PIN-Eingabe", die Sie in Banking-Apps sehen.

Sample app screenshot

0
Kevin Read

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

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

        }
    }
}
0
Nicolai

Ich weiß nicht, warum deine 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 Locale.ENGLISH Formatieren und sie dann in das EditText einfügen (auch als leere Zeichenfolge). Beispiel:

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

Wenn Sie dieser Lösung nachjagen, ist Ihr Ergebnis mit der angezeigten Tastatur kompatibel. Dann arbeiten Float- und Double-Zahlen in für Programmiersprachen typischer Weise mit Punkt statt Komma.

0
Dominik

Android hat einen eingebauten Zahlenformatierer. 

Sie können dies zu Ihrer EditText hinzufügen, um Dezimalzahlen und Kommas zuzulassen: Android:inputType="numberDecimal" und Android:digits="0123456789.,"

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

// 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;
}
0
Luis

Der beste Ansatz für dieses Problem ist meiner Meinung nach, einfach den InputFilter zu verwenden. Ein Nice Gist 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)});

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

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

Auf diese Weise, wenn Sie die Taste "." Drücken. in der weichen Tastatur passiert nichts; Nur Zahlen und Kommas sind erlaubt.

Alle anderen Posts hier hatten große Lücken. Hier ist eine Lösung, die Folgendes bewirkt:

  • Durch Erzwingen von Kommas oder Punkten basierend auf der Region können Sie nicht das Gegenteil eingeben.
  • Wenn der EditText mit einem bestimmten Wert beginnt, wird das richtige Trennzeichen nach Bedarf ersetzt.

In der XML:

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

Klassenvariable:

private boolean isDecimalSeparatorComma = false;

Suchen Sie in onCreate das im aktuellen Gebietsschema verwendete Trennzeichen:

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(",");
    }
}

Auch onCreate, Verwenden Sie dies, 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

auch onCreate, Add the Listeners

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

doSomething () - Beispiel, konvertiere zu Standardzeitraum für Datenmanipulation

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");
    }
}
0
Eli Fry

Ich habe mich entschieden, das Komma nur während der Bearbeitung in Punkt zu ändern. Hier ist meine schwierige 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 je nach Gebietsschema Kommas oder Punkte

0
KaMyLL

Es sind mehr als 8 Jahre vergangen und ich bin überrascht, dass dieses Problem noch nicht behoben ist ...
Ich habe mit diesem einfachen Problem zu kämpfen, da die von @Martin am häufigsten bewertete Antwort mehrere Trennzeichen eingeben kann, d. H. Der Benutzer kann "12 , 12,1, 21,2," eingeben.
Das zweite Problem ist auch, dass auf einigen Geräten comma nicht auf der numerischen Tastatur angezeigt wird (oder dass ein Punktknopf mehrfach gedrückt werden muss). 

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

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

Und der Textwächter:

  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([email protected])
            val formatted = toLocalizedDecimal(s.toString(), separator)
            setText(formatted)
            setSelection(formatted.length)
            addTextChangedListener([email protected])
        }
    }

    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(""))
        }
    }
}
0
Leo Droidcoder