Запятая десятичного разделителя (',') с номеромDecimal inputType в EditText - PullRequest
113 голосов
/ 29 сентября 2010

inputType numberDecimal в EditText использует точку '.' в качестве десятичного разделителя. В Европе принято использовать запятую «,» вместо. Несмотря на то, что моя локаль установлена ​​как немецкая, десятичный разделитель по-прежнему равен '.'

Есть ли способ получить запятую в качестве десятичного разделителя?

Ответы [ 20 ]

1 голос
/ 01 августа 2017

чтобы локализовать ввод, используйте:

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

и затем добавьте:

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

чем не забудьте заменить "," на "." так что Float или Double могут разобрать его без ошибок.

0 голосов
/ 24 декабря 2018

Прошло более 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(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(""))
        }
    }
}
0 голосов
/ 23 августа 2018

Я могу подтвердить, что предложенные исправления не работают на Samsung IME (по крайней мере, на S6 и S9) и, возможно, на LG. Они по-прежнему показывают точку в качестве десятичного разделителя независимо от локали. Переход на IME от Google исправляет это, но вряд ли подходит большинству разработчиков.

Это также не было исправлено в Oreo для этих клавиатур, так как это исправление, которое Samsung и / или LG должны сделать, а затем подтолкнуть даже к своим древним телефонам.

Вместо этого я выбрал проект с цифровой клавиатурой и добавил режим, в котором он ведет себя как IME: fork . Смотрите образец проекта для деталей. Это хорошо сработало для меня и похоже на многие фальшивые IME типа «ввод PIN-кода», которые вы видите в банковских приложениях.

Sample app screenshot

0 голосов
/ 29 января 2018

Мое решение:

  • В основной деятельности:

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

  • В XML-файле: android:imeOptions="flagNoFullscreen" android:inputType="numberDecimal"

и я взяла двойное в тексте редактирования в виде строки.

0 голосов
/ 11 января 2018

Я не знаю, почему ваши ответы такие сложные.Если в SDK есть ошибка, вы должны ее переопределить или обойти.

Я выбрал второй способ решения этой проблемы.Если вы отформатируете строку как Locale.ENGLISH, а затем поместите ее в EditText (даже как пустую строку).Пример:

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

В этом решении ваш результат совместим с показанной клавиатурой.Тогда числа с плавающей запятой и двойные числа работают в типичном для языков программирования стиле с точкой вместо запятой.

0 голосов
/ 05 сентября 2017

Я решил изменить запятую на точку только при редактировании. Вот мой хитрый и относительно простой обходной путь:

    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 будет использовать запятую или точку в зависимости от локали

0 голосов
/ 13 октября 2016

Я думаю, что это решение является менее сложным, чем другие, написанные здесь:

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

Таким образом, когда вы нажимаете '.'в мягкой клавиатуре ничего не происходит;разрешены только цифры и запятая.

0 голосов
/ 29 апреля 2019

Простое решение, сделать пользовательский контроль.(это сделано в 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);
            }

        }
    }
}
0 голосов
/ 01 июня 2019

Во всех других сообщениях здесь были серьезные дыры, поэтому вот решение, которое будет:

  • Применение запятых или точек, основанных на регионе, не позволит вам напечатать противоположное.
  • Если EditText начинается с некоторого значения, при необходимости он заменяет правильный разделитель.

В XML:

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

Переменная класса:

private boolean isDecimalSeparatorComma = false;

В onCreate найдите разделитель, используемый в текущей локали:

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

Также onCreate, Используйте это, чтобы обновить его, если вы загружаете текущее значение:

// 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

Также при создании, добавьте прослушиватели

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 () пример, преобразование в стандартный период для манипулирования данными

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 голосов
/ 13 марта 2017

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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...