inputType
numberDecimal
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?
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
}
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.
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;
}
});
Dies ist ein bekannter Fehler im Android SDK ..__ Die einzige Problemumgehung besteht darin, eine eigene Soft-Tastatur zu erstellen. Ein Implementierungsbeispiel finden Sie hier .
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;
}
}
}
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 :)
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));
}
});
}
Für Mono (Droid) -Lösungen:
decimal decimalValue = decimal.Parse(input.Text.Replace(",", ".") , CultureInfo.InvariantCulture);
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;
}
}
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.
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.
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.
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);
}
}
}
}
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.
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;
}
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:
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");
}
}
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
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(""))
}
}
}