Десятичный разделитель запятой (',') с номеромDecimal inputType в EditText
В inputType
numberDecimal
в EditText
используется точка '.' как десятичный разделитель. В Европе обычно используется запятая '' '. Несмотря на то, что мой локаль задан как немецкий, десятичный разделитель по-прежнему является "."
Есть ли способ получить запятую как десятичный разделитель?
Ответы
Ответ 1
Обходной путь (пока Google не исправит эту ошибку) должен использовать EditText
с android:inputType="numberDecimal"
и android:digits="0123456789.,"
.
Затем добавьте TextChangedListener в EditText со следующим afterTextChanged:
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
}
Ответ 2
Вариант предлагаемых здесь "цифровых" решений:
char separator = DecimalFormatSymbols.getInstance().getDecimalSeparator();
input.setKeyListener(DigitsKeyListener.getInstance("0123456789" + separator));
Принимая во внимание языковой разделитель.
Ответ 3
Следующая маска валюты кода для EditText ($ 123,125.155)
Xml Layout
<EditText
android:inputType="numberDecimal"
android:layout_height="wrap_content"
android:layout_width="200dp"
android:digits="0123456789.,$" />
код
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;
}
});
Ответ 4
Это известная ошибка в Android SDK. Единственный обходной путь - создать собственную программную клавиатуру. Вы можете найти пример реализации здесь.
Ответ 5
Ответ Martins не будет работать, если вы программно создаете EditText. Я пошел дальше и модифицировал включенный класс DigitsKeyListener
из API 14, чтобы разрешить как запятую, так и период как десятичный разделитель.
Чтобы использовать это, вызовите setKeyListener()
на EditText
, например
// Don't allow for signed input (minus), but allow for decimal points
editText.setKeyListener( new MyDigitsKeyListener( false, true ) );
Однако вам все равно придется использовать трюк Мартина в TextChangedListener
, где вы заменяете запятые на периоды
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
Вы можете использовать следующее обходное решение, которое также включает запятую в качестве допустимого ввода: -
Через XML:
<EditText
android:inputType="number"
android:digits="0123456789.," />
Программный:
EditText input = new EditText(THE_CONTEXT);
input.setKeyListener(DigitsKeyListener.getInstance("0123456789.,"));
Таким образом, система Android покажет клавиатуру номеров и позволит вводить запятую. Надеюсь, что это ответит на вопрос:)
Ответ 7
Для решений Mono (Droid):
decimal decimalValue = decimal.Parse(input.Text.Replace(",", ".") , CultureInfo.InvariantCulture);
Ответ 8
вы можете использовать следующие для разных локалей
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));
}
});
}
Ответ 9
Вы можете сделать следующее:
DecimalFormatSymbols d = DecimalFormatSymbols.getInstance(Locale.getDefault());
input.setFilters(new InputFilter[] { new DecimalDigitsInputFilter(5, 2) });
input.setKeyListener(DigitsKeyListener.getInstance("0123456789" + d.getDecimalSeparator()));
И тогда вы можете использовать входной фильтр:
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;
}
}
Ответ 10
чтобы локализовать использование вашего ввода:
char sep = DecimalFormatSymbols.getInstance().getDecimalSeparator();
а затем добавьте:
textEdit.setKeyListener(DigitsKeyListener.getInstance("0123456789" + sep));
чем не забудьте заменить "," на ".". поэтому Float или Double могут анализировать его без ошибок.
Ответ 11
ИМХО лучший подход для этой проблемы - просто использовать InputFilter. Хороший смысл здесь DecimalDigitsInputFilter. Тогда вы можете просто:
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)});
Ответ 12
Android имеет встроенный форматтер.
Вы можете добавить это в свой EditText
, чтобы разрешить десятичные знаки и запятые:
android:inputType="numberDecimal"
и android:digits="0123456789.,"
Затем где-то в вашем коде, когда пользователь нажимает кнопку "Сохранить" или после ввода текста (используйте прослушиватель).
// 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;
}
Ответ 13
Я решил изменить запятую только на то, чтобы редактировать ее. Вот мой сложный и относительный простой способ:
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 будет использовать запятую или точку, зависит от Locale
Ответ 14
Я не знаю, почему ваши ответы такие сложные. Если в SDK есть ошибка, вы должны ее переопределить или обойти.
Я выбрал второй способ решения этой проблемы. Если вы отформатируете строку как Locale.ENGLISH
а затем поместите ее в EditText
(даже в виде пустой строки). Пример:
String.format(Locale.ENGLISH,"%.6f", yourFloatNumber);
В погоне за этим решением ваш результат совместим с показанной клавиатурой. Тогда числа с плавающей запятой и двойные числа работают в типичном для языков программирования порядке с точкой вместо запятой.
Ответ 15
Мое решение:
-
По основному виду деятельности:
char separator =DecimalFormatSymbols.getInstance().getDecimalSeparator(); textViewPitchDeadZone.setKeyListener(DigitsKeyListener.getInstance("0123456789" + separator));
-
В XML файле: android:imeOptions="flagNoFullscreen" android:inputType="numberDecimal"
и я взял двойной в editText в качестве строки.
Ответ 16
Я могу подтвердить, что предложенные исправления не работают на IME Samsung (по крайней мере, на S6 и S9) и, возможно, на LG. Они по-прежнему показывают точку в качестве десятичного разделителя независимо от локали. Переход на Google IME исправляет это, но вряд ли подходит большинству разработчиков.
Он также не был исправлен в Oreo для этих клавиатур, поскольку это исправление, которое Samsung и/или LG должны сделать, а затем подтолкнуть даже к своим древним телефонам.
Вместо этого я раздвоил проект с цифровой клавиатурой и добавил режим, в котором он ведет себя как IME: fork. Смотрите образец проекта для деталей. Это сработало довольно хорошо для меня и похоже на многие поддельные IME типа "ввод PIN-кода", которые вы видите в банковских приложениях.
![Sample app screenshot]()
Ответ 17
Прошло более 8 лет, и я удивлен, что эта проблема еще не решена...
Я боролся с этой простой проблемой, так как наиболее одобренный ответ @Martin позволяет вводить несколько разделителей, то есть пользователь может ввести "12 ,,, 12,1, 21,2,"
Кроме того, вторая проблема заключается в том, что на некоторых устройствах запятая не отображается на цифровой клавиатуре (или требует многократного нажатия точечной кнопки).
Вот мое обходное решение, которое решает упомянутые проблемы и позволяет пользователю печатать "." и ',', но в EditText он увидит единственный десятичный разделитель, соответствующий текущей локали:
editText.apply { addTextChangedListener(DoubleTextChangedListener(this)) }
И наблюдатель текста:
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(""))
}
}
}
Ответ 18
Простое решение, сделать индивидуальный контроль. (это сделано в Xamarin Android, но должно легко портировать на Java)
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);
}
}
}
}
Ответ 19
Я думаю, что это решение менее сложно, чем другие, написанные здесь:
<EditText
android:inputType="numberDecimal"
android:digits="0123456789," />
Таким образом, когда вы нажимаете кнопку '.' в мягкой клавиатуре ничего не происходит; допускаются только числа и запятые.