Pemisah desimal koma (',') dengan numberTecimal inputType di EditText

133

Tanda inputType numberDecimalmasuk EditTextmenggunakan titik '.' sebagai pemisah desimal. Di Eropa, biasanya menggunakan koma ',' sebagai gantinya. Meskipun lokal saya disetel sebagai bahasa jerman, pemisah desimal masih menjadi '.'

Apakah ada cara untuk mendapatkan koma sebagai pemisah desimal?

mseo
sumber
1
bug ini akhirnya diperbaiki di Android O: issuetracker.google.com/issues/36907764
Lovis
mereka mengatakan itu diperbaiki tetapi saya tidak dapat mengkonfirmasi itu diperbaiki? Bisakah kamu?
sebastian
5
Saya dapat mengonfirmasi bahwa itu TIDAK diperbaiki, setidaknya pada Nexus 4 saya yang menjalankan Android 8.1 (alias LineageOS 15.1). Dengan Pengaturan-> Bahasa diatur ke Prancis (Prancis), sebuah EditText dengan android: inputType = "numberDecimal" menawarkan pemisah ',' (koma) tetapi masih menolak untuk menerima koma. Yang ditawarkan '.' (titik desimal) diterima. Sudah lebih dari 9 tahun sejak bug ini pertama kali dilaporkan. Apakah itu semacam catatan? Kuno.
pete

Jawaban:

105

Sebuah solusi (sampai Google memperbaiki bug ini) adalah dengan menggunakan EditTextdengan android:inputType="numberDecimal"dan android:digits="0123456789.,".

Kemudian tambahkan TextChangedListener ke EditText dengan afterTextChanged berikut:

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
sumber
1
@Zoombie agar tanda koma (,) ditampilkan di keyboard Anda bergantung pada bahasa yang ditetapkan pada perangkat Anda. Jika input Anda memiliki nomor numberDecimal dan bahasa Anda adalah bahasa Inggris (Amerika Serikat) itu akan ditampilkan pada perangkat Nexus (referensi). Mungkin saja perangkat non Nexus tidak menghargai ini
hcpl
11
Ini berfungsi, tetapi perlu diingat bahwa teks seperti "24,22.55" dapat digunakan. Anda mungkin perlu menambahkan beberapa validasi tambahan untuk memperbaikinya!
dimsuz
8
Apakah ini masih jalan yang harus ditempuh?
Willi Mentzel
Lebih baik lagi, gunakan char localizedSeparator = DecimalFormatSymbols.getInstance (). GetDecimalSeparator (); localizedFloatString = localizedFloatString.replace ('.', localizedSeparator);
southerton
4
Sepertinya ini hanya memperdagangkan satu bug untuk bug lainnya. Seperti yang diterapkan di atas, ini akan berfungsi untuk lokal yang menggunakan, bukan. dengan biaya kebalikan yang lebih umum di seluruh dunia. Tweak @ southerton memang membantu, namun pengguna Anda mungkin terkejut ketika mereka menekan a. dan memiliki, muncul di input.
Nick
30

Variasi pada solusi 'digit' yang ditawarkan di sini:

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

Dengan mempertimbangkan pemisah lokal.

dstibbe
sumber
Ini adalah jawaban paling bersih untuk pertanyaan awal. Terima kasih
peter.bartos
Tempatkan ini di onCreate (), ini adalah cara untuk pergi, IMHO.
TechNyquist
6
Saya suka ini, tapi hati-hati ... ada keyboard yang tidak peduli dengan lokal pengguna, jadi pengguna yang tidak memiliki kunci ,di keyboard mereka. Contoh: Keyboard Samsung (KitKat).
Brais Gabin
2
Ini akan memungkinkan pemisah desimal duplikat. Lihat jawaban di bawah ini untuk menanganinya: stackoverflow.com/a/45384821/6138589
Esdras Lopez
19

Kode Mask Mata Uang Berikut untuk EditText ($ 123.125.155)

Tata Letak Xml

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

Kode

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;
        }
    });
pengguna1269737
sumber
16

Ini adalah bug yang dikenal di Android SDK. Satu-satunya solusi adalah membuat keyboard lunak Anda sendiri. Anda dapat menemukan contoh implementasi di sini .

EricLarch
sumber
15
Apakah ada berita setelah empat tahun?
Antonio Sesto
Mengalami ini di Xamarin. Bentuk juga. Budaya adalah {se-SV} dan numpad menunjukkan bot "," (pemisah desimal) dan "." (ribu pemisah grup) tetapi setelah menekan tombol "," tidak ada yang dimasukkan dalam bidang teks dan tidak ada peristiwa yang diangkat
joacar
Saya dapat mengkonfirmasi bahwa bug itu masih ada.
Lensflare
diperbaiki dalam pratinjau pengembang Android O
R00We
6

Jawaban Martins tidak akan berfungsi jika Anda membuat EditText secara terprogram. Saya melanjutkan dan memodifikasi DigitsKeyListenerkelas yang disertakan dari API 14 untuk memungkinkan koma dan periode sebagai pemisah desimal.

Untuk menggunakan ini, sebut setKeyListener()pada EditText, misalnya

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

Namun, Anda masih harus menggunakan trik Martin di TextChangedListenermana Anda mengganti koma dengan titik

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
sumber
dari doc: KeyListener hanya boleh digunakan untuk kasus-kasus di mana aplikasi memiliki keypad di layar sendiri dan juga ingin memproses acara papan ketik yang keras agar sesuai dengannya. developer.android.com/reference/android/text/method/…
Loda
6

Anda dapat menggunakan yang berikut untuk lokal yang berbeda

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
sumber
Ini adalah solusi terbaik bagi saya, tetapi ada masalah dengan beberapa ponsel, misalnya Samsung, yang tidak menunjukkan koma "," di keyboard. Jadi saya mengubah ini untuk memungkinkan koma dan titik, tetapi kemudian mengganti sesuai dengan lokal
Riccardo Casatta
5

Anda dapat menggunakan solusi berikut untuk memasukkan koma sebagai input yang valid: -

Melalui XML:

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

Secara terprogram:

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

Dengan cara ini sistem Android akan menampilkan keyboard angka dan memungkinkan input koma. Semoga ini menjawab pertanyaan :)

MiaN KhaLiD
sumber
Dengan solusi ini saat Anda mengetuk ",", tetapi hasil edit teks menunjukkan "."
Mara Jimenez
2

Untuk solusi Mono (Droid):

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

Anda dapat melakukan hal berikut:

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

Dan kemudian Anda bisa menggunakan filter input:

    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
sumber
mungkin ada ruang antara seribu dan seratus, pola ini akan menolak input yang diformat
Eric Zhao
1

IMHO pendekatan terbaik untuk masalah ini adalah dengan hanya menggunakan InputFilter. Inti yang bagus ada di sini DecimalDigitsInputFilter . Maka Anda bisa:

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
sumber
Ini bekerja seperti pesona, terima kasih! (setelah begitu banyak solusi yang salah di atas ... :() Tapi saya punya pertanyaan: Bagaimana saya dapat mencapai koma itu (",") yang ditampilkan di layar bukan titik (".") karena di Hongaria kami menggunakan koma sebagai pemisah desimal .
Abigail La'Fay
1
Android: digit = "0123456789," pengaturan dapat ditambahkan ke EditText. Selain itu, alih-alih mengembalikan nol dalam DecimalDigitsInputFilter, Anda dapat mengembalikan source.replace (".", ",") Sesuai dengan jawaban stackoverflow.com/a/40020731/1510222 tidak ada cara untuk menyembunyikan titik di keyboard standar
Arkadiusz Cieśliński
1

untuk melokalkan penggunaan input Anda:

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

lalu tambahkan:

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

daripada jangan lupa untuk mengganti "," dengan "." jadi Float atau Double dapat menguraikannya tanpa kesalahan.

Milos Simic Simo
sumber
1
Solusi ini memungkinkan Anda memasukkan beberapa koma
Leo Droidcoder
1

Semua posting lain di sini memiliki lubang besar di dalamnya, jadi inilah solusi yang akan:

  • Menerapkan koma atau periode berdasarkan wilayah, tidak akan membiarkan Anda mengetik yang sebaliknya.
  • Jika EditText dimulai dengan beberapa nilai, itu akan menggantikan pemisah yang benar sesuai kebutuhan.

Dalam XML:

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

Variabel kelas:

private boolean isDecimalSeparatorComma = false;

Di onCreate, cari pemisah yang digunakan di lokal saat ini:

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

Juga diCreate, Gunakan ini untuk memperbaruinya jika Anda memuat dalam nilai saat ini:

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

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

Contoh doSomething (), konversikan ke periode standar untuk manipulasi data

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

Android memiliki pemformat angka bawaan.

Anda dapat menambahkan ini ke Anda EditTextuntuk memungkinkan desimal dan koma: android:inputType="numberDecimal"danandroid:digits="0123456789.,"

Kemudian di suatu tempat dalam kode Anda, baik ketika pengguna mengklik simpan atau setelah teks dimasukkan (gunakan pendengar).

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

Saya memutuskan untuk mengubah koma ke titik hanya saat mengedit. Berikut ini solusi sederhana dan rumit yang saya lakukan:

    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 akan menggunakan koma atau titik tergantung pada Lokal

KaMyLL
sumber
0

Saya tidak tahu mengapa jawaban Anda sangat rumit. Jika ada bug di SDK Anda harus menimpanya atau berkeliling.

Saya telah memilih cara kedua untuk menyelesaikan masalah itu. Jika Anda memformat string Anda sebagai Locale.ENGLISHdan kemudian memasukkannya ke EditText(bahkan sebagai string kosong). Contoh:

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

Mengejar solusi itu hasil Anda kompatibel dengan keyboard yang ditampilkan. Kemudian float dan angka ganda bekerja secara tipikal untuk bahasa pemrograman dengan titik alih-alih koma.

Dominik
sumber
0

Solusi saya adalah:

  • Dalam kegiatan utama:

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

  • Dalam file xml: android:imeOptions="flagNoFullscreen" android:inputType="numberDecimal"

dan saya mengambil ganda di editText sebagai String.

Lseb
sumber
0

Saya dapat mengonfirmasi bahwa perbaikan yang diajukan tidak berfungsi pada IME Samsung (setidaknya pada S6 dan S9) dan mungkin LG. Mereka masih menunjukkan titik sebagai pemisah desimal terlepas dari lokal. Beralih ke IME Google memperbaikinya tetapi hampir tidak menjadi pilihan bagi sebagian besar pengembang.

Ini juga belum diperbaiki di Oreo untuk keyboard ini karena ini adalah perbaikan yang harus dilakukan oleh Samsung dan / atau LG dan kemudian mendorong bahkan ke handset kuno mereka.

Saya telah bukannya bercabang yang proyek nomor-keyboard dan menambahkan modus mana berperilaku seperti IME: garpu . Lihat contoh proyek untuk detailnya. Ini telah bekerja cukup baik untuk saya dan mirip dengan banyak IME palsu "entri PIN" yang Anda lihat di aplikasi perbankan.

Contoh tangkapan layar aplikasi

Kevin Read
sumber
0

Sudah lebih dari 8 tahun berlalu dan saya terkejut, masalah ini belum diperbaiki ...
Saya kesulitan dengan masalah sederhana ini karena jawaban yang paling banyak dipilih oleh @Martin memungkinkan mengetik beberapa pemisah, yaitu pengguna dapat mengetikkan "12 ,,, ,,, 12,1,, 21,2, "
Juga, perhatian kedua adalah bahwa pada beberapa perangkat koma tidak ditampilkan pada keyboard numerik (atau memerlukan beberapa penekanan tombol dot)

Ini adalah solusi penyelesaian masalah saya, yang memecahkan masalah yang disebutkan dan memungkinkan pengguna mengetik '.' dan ',', tetapi dalam EditText ia akan melihat satu-satunya pemisah desimal yang sesuai dengan lokal saat ini:

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

Dan pengamat teks:

  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
sumber
0

Solusi sederhana, buat kontrol khusus. (ini dibuat di Xamarin android tetapi harus port dengan mudah ke 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);
            }

        }
    }
}
Nicolai
sumber
0

Anda dapat menggunakan inputType="phone", namun dalam hal ini Anda harus berurusan dengan banyak ,atau .hadir, sehingga validasi tambahan akan diperlukan.

medula oblongata jack
sumber
-1

Saya pikir solusi ini kurang kompleks daripada yang lain yang ditulis di sini:

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

Dengan cara ini saat Anda menekan '.' di keyboard lunak tidak ada yang terjadi; hanya angka dan koma yang diizinkan.

Jorge Alcolea Coronel
sumber
4
jika Anda melakukan ini maka Anda hanya akan menghancurkan semua lokal yang menggunakan '.' sebagai gantinya.
Nick