Cara yang lebih baik untuk Memformat EditText Input Mata Uang?

91

Saya memiliki editText, nilai awal adalah $ 0,00. Saat Anda menekan 1, nilainya berubah menjadi $ 0,01. Tekan 4, hasilnya $ 0,14. Tekan 8, $ 1,48. Tekan backspace, $ 0,14, dll.

Itu berhasil, masalahnya adalah, jika seseorang secara manual memposisikan kursor, masalah terjadi dalam pemformatan. Jika mereka menghapus desimal, itu tidak akan kembali. Jika mereka meletakkan kursor di depan desimal dan tipe 2, itu akan menampilkan $ 02, bukan $ 2.00. Jika mereka mencoba untuk menghapus $ itu akan menghapus sebuah digit, misalnya.

Ini kode yang saya gunakan, saya menghargai saran apa pun.

mEditPrice.setRawInputType(Configuration.KEYBOARD_12KEY);
    public void priceClick(View view) {
    mEditPrice.addTextChangedListener(new TextWatcher(){
        DecimalFormat dec = new DecimalFormat("0.00");
        @Override
        public void afterTextChanged(Editable arg0) {
        }
        @Override
        public void beforeTextChanged(CharSequence s, int start,
                int count, int after) {
        }
        @Override
        public void onTextChanged(CharSequence s, int start,
                int before, int count) {
            if(!s.toString().matches("^\\$(\\d{1,3}(\\,\\d{3})*|(\\d+))(\\.\\d{2})?$"))
            {
                String userInput= ""+s.toString().replaceAll("[^\\d]", "");
                if (userInput.length() > 0) {
                    Float in=Float.parseFloat(userInput);
                    float percen = in/100;
                    mEditPrice.setText("$"+dec.format(percen));
                    mEditPrice.setSelection(mEditPrice.getText().length());
                }
            }
        }
    });
Roger
sumber
1
Maafkan ketidaktahuan saya, tetapi apakah cuplikan kode ini berasal dari salah satu metode siklus hidup aktivitas, atau apakah mereka dalam kelas khusus yang Anda buat? Bisakah Anda memberikan contoh kode yang lebih lengkap? Terima kasih!
Argus9
Ini berfungsi untuk saya, saya telah mencoba lib eksternal ini android-arsenal.com/details/1/5374
pravin maske

Jawaban:

153

Saya menguji metode Anda, tetapi gagal ketika saya menggunakan angka-angka besar ... Saya membuat ini:

private String current = "";
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
    if(!s.toString().equals(current)){
       [your_edittext].removeTextChangedListener(this);

       String cleanString = s.toString().replaceAll("[$,.]", "");
                
       double parsed = Double.parseDouble(cleanString);
       String formatted = NumberFormat.getCurrencyInstance().format((parsed/100));
                    
       current = formatted;
       [your_edittext].setText(formatted);
       [your_edittext].setSelection(formatted.length());
       
       [your_edittext].addTextChangedListener(this);
    }
}

Varian Kotlin:

private var current: String = ""

         override fun onTextChanged(
            s: CharSequence,
            start: Int,
            before: Int,
            count: Int
        ) {
            if (s.toString() != current) {
                discount_amount_edit_text.removeTextChangedListener(this)

                val cleanString: String = s.replace("""[$,.]""".toRegex(), "")

                val parsed = cleanString.toDouble()
                val formatted = NumberFormat.getCurrencyInstance().format((parsed / 100))

                current = formatted
                discount_amount_edit_text.setText(formatted)
                discount_amount_edit_text.setSelection(formatted.length)

                discount_amount_edit_text.addTextChangedListener(this)
            }
        }
Guilherme Oliveira
sumber
36
Mungkin lebih baik melakukan hal berikut daripada mengasumsikan simbol dolar: String replaceable = String.format("[%s,.]", NumberFormat.getCurrencyInstance().getCurrency().getSymbol()); String cleanString = s.toString().replaceAll(replaceable, "");
craigp
6
Hmm, sebenarnya saya sudah mencobanya sekarang, pola regex dari replaceAll akan terlihat seperti ini, untuk menangani spasi juga: String replaceable = String.format("[%s,.\\s]", NumberFormat.getCurrencyInstance().getCurrency().getSymbol());
craigp
6
Bukankah disarankan untuk tidak membuat perubahan di onTextChanged() and rather to do so in afterTextChanged () `
codinguser
3
Saya tertarik untuk mengetahui mengapa pendengar yang diubah teks dihapus dan kemudian ditambahkan kembali setiap kali? Bagi saya ini berfungsi jika hanya ditambahkan sekali (dan saya memindahkan perubahan ke afterTextChanged)
Daniel Wilson
5
Saya tidak bekerja ketika Anda meletakkan 1 -> 0 -> 0 untuk mendapatkan 1,00. Itu karena Anda sampai pada titik di mana 0,1 diubah menjadi string 010 dan 010 menjadi double10. 10 / 100 = 0,1Anda tidak bisa melewatinya.
JakubW
30

Berdasarkan beberapa jawaban di atas, saya membuat MoneyTextWatcher yang akan Anda gunakan sebagai berikut:

priceEditText.addTextChangedListener(new MoneyTextWatcher(priceEditText));

dan inilah kelasnya:

public class MoneyTextWatcher implements TextWatcher {
    private final WeakReference<EditText> editTextWeakReference;

    public MoneyTextWatcher(EditText editText) {
        editTextWeakReference = new WeakReference<EditText>(editText);
    }

    @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) {
        EditText editText = editTextWeakReference.get();
        if (editText == null) return;
        String s = editable.toString();
        if (s.isEmpty()) return;
        editText.removeTextChangedListener(this);
        String cleanString = s.replaceAll("[$,.]", "");
        BigDecimal parsed = new BigDecimal(cleanString).setScale(2, BigDecimal.ROUND_FLOOR).divide(new BigDecimal(100), BigDecimal.ROUND_FLOOR);
        String formatted = NumberFormat.getCurrencyInstance().format(parsed);
        editText.setText(formatted);
        editText.setSelection(formatted.length());
        editText.addTextChangedListener(this);
    }
}
ToddH
sumber
Saya telah menggunakan ini untuk sementara waktu sekarang tetapi baru-baru ini menemukan masalah kecil, jika Anda menahan tombol hapus pada beberapa keyboard, itu akan menghapus seluruh kata / kelompok teks dan penyebabnyajava.lang.NumberFormatException: Bad offset/length
BluGeni
1
Ini bekerja dengan sempurna untuk saya! Perhatian pada 'editText.setSelection (formatted.length ());' harus diamati ke properti instance 'maxLength' dari EditText yang dimaksud. maxLength == 13; formatted.length () == 14; Jika 'formatted.length' lebih besar dari 'maxLength' kesalahan berikut terjadi: IndexOutOfBoundsException: setSpan (14 ... 14) mengakhiri panjang melebihi 13 tks
GFPF
1
@BluGeni untuk memperbaikinya cukup tambahkan pemeriksaan s.isEmpty sebelum menghapus listener perubahan teks if (s.isEmpty ()) return; editText.removeTextChangedListener (ini); Juga di baris cleanString, s.toString () redundan
Mike Baglio Jr.
1
jawaban terbaik daripada hanya satu saran adalah mengubah .replaceAll ("[$ ...) untuk -> .replaceAll (" [^ \\ d.] "," "); karena im mata uang lain Anda memiliki karakter lain selain hanya $, seperti dalam kasus saya adalah R $ (brazilian)
user2582318
1
maaf saran yang benar adalah yang ini -> .replaceAll("[^0-9]", ""), yang di atas memiliki batas 9.999.999 -_-
pengguna2582318
21

Ini kebiasaan saya CurrencyEditText

import android.content.Context;import android.graphics.Rect;import android.text.Editable;import android.text.InputFilter;import android.text.InputType;import android.text.TextWatcher;
import android.util.AttributeSet;import android.widget.EditText;import java.math.BigDecimal;import java.math.RoundingMode;
import java.text.DecimalFormat;import java.text.DecimalFormatSymbols;
import java.util.Locale;

/**
 * Some note <br/>
 * <li>Always use locale US instead of default to make DecimalFormat work well in all language</li>
 */
public class CurrencyEditText extends android.support.v7.widget.AppCompatEditText {
    private static String prefix = "VND ";
    private static final int MAX_LENGTH = 20;
    private static final int MAX_DECIMAL = 3;
    private CurrencyTextWatcher currencyTextWatcher = new CurrencyTextWatcher(this, prefix);

    public CurrencyEditText(Context context) {
        this(context, null);
    }

    public CurrencyEditText(Context context, AttributeSet attrs) {
        this(context, attrs, android.support.v7.appcompat.R.attr.editTextStyle);
    }

    public CurrencyEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
        this.setHint(prefix);
        this.setFilters(new InputFilter[] { new InputFilter.LengthFilter(MAX_LENGTH) });
    }

    @Override
    protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
        super.onFocusChanged(focused, direction, previouslyFocusedRect);
        if (focused) {
            this.addTextChangedListener(currencyTextWatcher);
        } else {
            this.removeTextChangedListener(currencyTextWatcher);
        }
        handleCaseCurrencyEmpty(focused);
    }

    /**
     * When currency empty <br/>
     * + When focus EditText, set the default text = prefix (ex: VND) <br/>
     * + When EditText lose focus, set the default text = "", EditText will display hint (ex:VND)
     */
    private void handleCaseCurrencyEmpty(boolean focused) {
        if (focused) {
            if (getText().toString().isEmpty()) {
                setText(prefix);
            }
        } else {
            if (getText().toString().equals(prefix)) {
                setText("");
            }
        }
    }

    private static class CurrencyTextWatcher implements TextWatcher {
        private final EditText editText;
        private String previousCleanString;
        private String prefix;

        CurrencyTextWatcher(EditText editText, String prefix) {
            this.editText = editText;
            this.prefix = prefix;
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            // do nothing
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            // do nothing
        }

        @Override
        public void afterTextChanged(Editable editable) {
            String str = editable.toString();
            if (str.length() < prefix.length()) {
                editText.setText(prefix);
                editText.setSelection(prefix.length());
                return;
            }
            if (str.equals(prefix)) {
                return;
            }
            // cleanString this the string which not contain prefix and ,
            String cleanString = str.replace(prefix, "").replaceAll("[,]", "");
            // for prevent afterTextChanged recursive call
            if (cleanString.equals(previousCleanString) || cleanString.isEmpty()) {
                return;
            }
            previousCleanString = cleanString;

            String formattedString;
            if (cleanString.contains(".")) {
                formattedString = formatDecimal(cleanString);
            } else {
                formattedString = formatInteger(cleanString);
            }
            editText.removeTextChangedListener(this); // Remove listener
            editText.setText(formattedString);
            handleSelection();
            editText.addTextChangedListener(this); // Add back the listener
        }

        private String formatInteger(String str) {
            BigDecimal parsed = new BigDecimal(str);
            DecimalFormat formatter =
                    new DecimalFormat(prefix + "#,###", new DecimalFormatSymbols(Locale.US));
            return formatter.format(parsed);
        }

        private String formatDecimal(String str) {
            if (str.equals(".")) {
                return prefix + ".";
            }
            BigDecimal parsed = new BigDecimal(str);
            // example pattern VND #,###.00
            DecimalFormat formatter = new DecimalFormat(prefix + "#,###." + getDecimalPattern(str),
                    new DecimalFormatSymbols(Locale.US));
            formatter.setRoundingMode(RoundingMode.DOWN);
            return formatter.format(parsed);
        }

        /**
         * It will return suitable pattern for format decimal
         * For example: 10.2 -> return 0 | 10.23 -> return 00, | 10.235 -> return 000
         */
        private String getDecimalPattern(String str) {
            int decimalCount = str.length() - str.indexOf(".") - 1;
            StringBuilder decimalPattern = new StringBuilder();
            for (int i = 0; i < decimalCount && i < MAX_DECIMAL; i++) {
                decimalPattern.append("0");
            }
            return decimalPattern.toString();
        }

        private void handleSelection() {
            if (editText.getText().length() <= MAX_LENGTH) {
                editText.setSelection(editText.getText().length());
            } else {
                editText.setSelection(MAX_LENGTH);
            }
        }
    }
}

Gunakan dalam XML seperti

 <...CurrencyEditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        />

Anda harus mengedit 2 konstanta di bawah ini agar sesuai dengan proyek Anda

private static String prefix = "VND ";
private static final int MAX_DECIMAL = 3;

masukkan deskripsi gambar di sini

Demo di github

Phan Van Linh
sumber
2
Ini luar biasa!
YTerle
1
Saya menemukan bahwa setelah mengetik untuk mencapai jumlah maksimum tempat desimal, mencoba memasukkan angka 5-9 akan menambah tempat desimal terakhir sebesar 1 ... pembulatannya! Fix saya adalah untuk memanggil formatter.setRoundingMode(RoundingMode.DOWN);dalam formatDecimalmetode.
BW
@bwicks terima kasih banyak telah menemukan masalahnya. Saya telah menyetujui suntingan Anda
Phan Van Linh
bagaimana cara menempatkan simbol mata uang dari VND ??
Mayur Karmur
1
Ide perbaikan lain: Jika pengguna masuk $., ketika kita mendapatkan nilai mentah sebagai .dan mengurai ke Ganda, itu memberi NFE. Untuk memperbaikinya, saya dibuat formatDecimal()untuk kembali prefix + "0.";dan berubah #,###.ke #,##0.dalam formatDecimal(). Ini juga terlihat lebih baik ketika pengguna memasukkan tempat desimal saja. Ini menunjukkan sebagai $0.25gantinya $.25.
Gokhan Arik
13

Sebenarnya, solusi yang diberikan sebelumnya tidak berfungsi. Tidak berfungsi jika Anda ingin memasukkan 100.00.

Menggantikan:

double parsed = Double.parseDouble(cleanString);
String formato = NumberFormat.getCurrencyInstance().format((parsed/100));

Dengan:

BigDecimal parsed = new BigDecimal(cleanString).setScale(2,BigDecimal.ROUND_FLOOR).divide(new BigDecimal(100),BigDecimal.ROUND_FLOOR);                
String formato = NumberFormat.getCurrencyInstance().format(parsed);

Saya harus mengatakan bahwa saya membuat beberapa modifikasi untuk kode saya. Masalahnya adalah Anda harus menggunakan BigDecimal

sfratini.dll
sumber
6

Saya mengubah kelas dengan mengimplementasikan TextWatcher untuk menggunakan format mata uang Brasil dan menyesuaikan posisi kursor saat mengedit nilainya.

kelas publik MoneyTextWatcher mengimplementasikan TextWatcher {

    pribadi EditText editText;

    private String lastAmount = "";

    private int lastCursorPosition = -1;

    public MoneyTextWatcher (EditText editText) {
        super();
        this.editText = editText;
    }

    @Mengesampingkan
    public void onTextChanged (jumlah CharSequence, int mulai, int sebelumnya, int count) {

        if (! amount.toString (). sama dengan (lastAmount)) {

            String cleanString = clearCurrencyToNumber (jumlah.toString ());

            coba {

                String formattedAmount = transformToCurrency (cleanString);
                editText.removeTextChangedListener (ini);
                editText.setText (formattedAmount);
                editText.setSelection (formattedAmount.length ());
                editText.addTextChangedListener (ini);

                if (lastCursorPosition! = lastAmount.length () && lastCursorPosition! = -1) {
                    int lengthDelta = formattedAmount.length () - lastAmount.length ();
                    int newCursorOffset = max (0, min (formattedAmount.length (), lastCursorPosition + lengthDelta));
                    editText.setSelection (newCursorOffset);
                }
            } catch (Exception e) {
               // mencatat sesuatu
            }
        }
    }

    @Mengesampingkan
    public void afterTextChanged (Dapat diedit) {
    }

    @Mengesampingkan
    public void beforeTextChanged (CharSequence s, int start, int count, int after) {
        Nilai string = s.toString ();
        if (! value.equals ("")) {
            String cleanString = clearCurrencyToNumber (nilai);
            String formattedAmount = transformToCurrency (cleanString);
            lastAmount = formattedAmount;
            lastCursorPosition = editText.getSelectionStart ();
        }
    }

    public static String clearCurrencyToNumber (String currencyValue) {
        Hasil string = null;

        jika (currencyValue == null) {
            hasil = "";
        } lain {
            hasil = currencyValue.replaceAll ("[(az) | (AZ) | ($ ,.)]", "");
        }
        hasil pengembalian;
    }

    public static boolean isCurrencyValue (String currencyValue, boolean podeSerZero) {
        hasil boolean;

        if (currencyValue == null || currencyValue.length () == 0) {
            hasil = salah;
        } lain {
            if (! podeSerZero && currencyValue.equals ("0,00")) {
                hasil = salah;
            } lain {
                hasil = benar;
            }
        }
        hasil pengembalian;
    }

    public static String transformToCurrency (nilai String) {
        parsing ganda = Double.parseDouble (nilai);
        String formatted = NumberFormat.getCurrencyInstance (Lokal baru ("pt", "BR")). Format ((parsed / 100));
        formatted = formatted.replaceAll ("[^ (0-9) (.,)]", "");
        kembali diformat;
    }
}
Henrique Ho
sumber
Di baris ini "int newCursorOffset = max (0, min (formattedAmount.length (), lastCursorPosition + lengthDelta));" Jenis objek apa max dan min?
Arthur Melo
2
@ArthurMelo Its, Math.max, Math.min Terima kasih kodenya, dan sepertinya gagal saat menghapus koma dari edittext.
Marcos Vasconcelos
4

Saya membangun jawaban Guilhermes, tetapi saya mempertahankan posisi kursor dan juga memperlakukan titik secara berbeda - dengan cara ini jika pengguna mengetik setelah titik, itu tidak mempengaruhi angka sebelum periode, saya menemukan bahwa ini memberikan masukan yang sangat halus .

    [yourtextfield].addTextChangedListener(new TextWatcher()
    {
        NumberFormat currencyFormat = NumberFormat.getCurrencyInstance();
        private String current = "";

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count)
        {
            if(!s.toString().equals(current))
            {
                   [yourtextfield].removeTextChangedListener(this);

                   int selection = [yourtextfield].getSelectionStart();


                   // We strip off the currency symbol
                   String replaceable = String.format("[%s,\\s]", NumberFormat.getCurrencyInstance().getCurrency().getSymbol());
                   String cleanString = s.toString().replaceAll(replaceable, "");

                   double price;

                   // Parse the string                     
                   try
                   {
                       price = Double.parseDouble(cleanString);
                   }
                   catch(java.lang.NumberFormatException e)
                   {
                       price = 0;
                   }

                   // If we don't see a decimal, then the user must have deleted it.
                   // In that case, the number must be divided by 100, otherwise 1
                   int shrink = 1;
                   if(!(s.toString().contains(".")))
                   {
                       shrink = 100;
                   }

                   // Reformat the number
                   String formated = currencyFormat.format((price / shrink));

                   current = formated;
                   [yourtextfield].setText(formated);
                   [yourtextfield].setSelection(Math.min(selection, [yourtextfield].getText().length()));

                   [yourtextfield].addTextChangedListener(this);
                }
        }


        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after)
        {

        }


        @Override
        public void afterTextChanged(Editable s)
        {
        }
    });
genixpro
sumber
itu sangat membantu saya. Terima kasih @genixpro
Harin Kaklotar
Saya suka ide Anda, tetapi akan terlihat lebih mulus jika Anda menyimpan jumlah digit setelah kursor, lalu setSelection (panjang - setelah).
Alpha Huang
Sangat menarik! Penggunaan dapat diganti berfungsi pada perangkat fisik saya, tetapi tidak berfungsi pada emulator.
Aliton Oliveira
4

Meskipun ada banyak jawaban di sini, saya ingin membagikan kode yang saya temukan di sini karena saya yakin ini adalah jawaban yang paling kuat dan bersih.

class CurrencyTextWatcher implements TextWatcher {

    boolean mEditing;

    public CurrencyTextWatcher() {
        mEditing = false;
    }

    public synchronized void afterTextChanged(Editable s) {
        if(!mEditing) {
            mEditing = true;

            String digits = s.toString().replaceAll("\\D", "");
            NumberFormat nf = NumberFormat.getCurrencyInstance();
            try{
                String formatted = nf.format(Double.parseDouble(digits)/100);
                s.replace(0, s.length(), formatted);
            } catch (NumberFormatException nfe) {
                s.clear();
            }

            mEditing = false;
        }
    }

    public void beforeTextChanged(CharSequence s, int start, int count, int after) { }

    public void onTextChanged(CharSequence s, int start, int before, int count) { }

}

semoga membantu.

Kayvan N
sumber
Bukankah itu menghilangkan koma desimal? Jadi Anda tidak akan bisa membedakan antara $ 100 dan $ 10.000 - kecuali saya melewatkan sesuatu.
nasch
2
ini jawaban yang sempurna! bekerja untuk saya. saya, pikirkan saja berapa banyak waktu yang saya habiskan untuk jawaban itu dan akhirnya menggulir ke bawah ke bawah dan menemukan yang saya inginkan.
Ge Rong
Saya senang ini membantu Anda.
Kayvan N
@nasch Ini adalah TextWatcher dan memformat teks sebagai tipe pengguna yang mencegah kasus yang Anda sebutkan.
Kayvan N
@KayvanN Saya tahu apa itu TextWatcher. replaceAll("\\D", "")akan menghapus semua yang bukan digit, jadi "$ 100.00" dan "$ 10.000" keduanya menjadi "10000". Tampaknya Anda mengandalkan masukan untuk memasukkan sen. Jadi kalau dijamin, bagus tapi kalau tidak saya rasa akan ada masalah.
nasch
4

Oke, berikut adalah cara yang lebih baik untuk menangani format Mata Uang, menghapus penekanan tombol mundur. Kode ini didasarkan pada kode @androidcurious 'di atas ... Namun, berkaitan dengan beberapa masalah terkait penghapusan mundur dan beberapa pengecualian parse: http://miguelt.blogspot.ca/2013/01/textwatcher-for-currency-masksformatting .html [UPDATE] Solusi sebelumnya memiliki beberapa masalah ... Ini adalah solutoin yang lebih baik: http://miguelt.blogspot.ca/2013/02/update-textwatcher-for-currency.html Dan ... berikut adalah detailnya:

Pendekatan ini lebih baik karena menggunakan mekanisme Android konvensional. Idenya adalah untuk memformat nilai setelah pengguna ada View.

Tentukan InputFilter untuk membatasi nilai numerik - ini diperlukan dalam banyak kasus karena layar tidak cukup besar untuk mengakomodasi tampilan EditText yang panjang. Ini bisa menjadi kelas dalam statis atau hanya kelas biasa lainnya:

/** Numeric range Filter. */
class NumericRangeFilter implements InputFilter {
    /** Maximum value. */
    private final double maximum;
    /** Minimum value. */
    private final double minimum;
    /** Creates a new filter between 0.00 and 999,999.99. */
    NumericRangeFilter() {
        this(0.00, 999999.99);
    }
    /** Creates a new filter.
     * @param p_min Minimum value.
     * @param p_max Maximum value. 
     */
    NumericRangeFilter(double p_min, double p_max) {
        maximum = p_max;
        minimum = p_min;
    }
    @Override
    public CharSequence filter(
            CharSequence p_source, int p_start,
            int p_end, Spanned p_dest, int p_dstart, int p_dend
    ) {
        try {
            String v_valueStr = p_dest.toString().concat(p_source.toString());
            double v_value = Double.parseDouble(v_valueStr);
            if (v_value<=maximum && v_value>=minimum) {
                // Returning null will make the EditText to accept more values.
                return null;
            }
        } catch (NumberFormatException p_ex) {
            // do nothing
        }
        // Value is out of range - return empty string.
        return "";
    }
}

Tentukan kelas (statis batin atau hanya kelas) yang akan mengimplementasikan View.OnFocusChangeListener. Perhatikan bahwa saya menggunakan kelas Utils - implementasinya dapat ditemukan di "Jumlah, Pajak".

/** Used to format the amount views. */
class AmountOnFocusChangeListener implements View.OnFocusChangeListener {
    @Override
    public void onFocusChange(View p_view, boolean p_hasFocus) {
        // This listener will be attached to any view containing amounts.
        EditText v_amountView = (EditText)p_view;
        if (p_hasFocus) {
            // v_value is using a currency mask - transfor over to cents.
            String v_value = v_amountView.getText().toString();
            int v_cents = Utils.parseAmountToCents(v_value);
            // Now, format cents to an amount (without currency mask)
            v_value = Utils.formatCentsToAmount(v_cents);
            v_amountView.setText(v_value);
            // Select all so the user can overwrite the entire amount in one shot.
            v_amountView.selectAll();
        } else {
            // v_value is not using a currency mask - transfor over to cents.
            String v_value = v_amountView.getText().toString();
            int v_cents = Utils.parseAmountToCents(v_value);
            // Now, format cents to an amount (with currency mask)
            v_value = Utils.formatCentsToCurrency(v_cents);
            v_amountView.setText(v_value);
        }
    }
}

Kelas ini akan menghapus format mata uang saat mengedit - mengandalkan mekanisme standar. Saat pengguna keluar, format mata uang diterapkan kembali.

Lebih baik menentukan beberapa variabel statis untuk meminimalkan jumlah instance:

   static final InputFilter[] FILTERS = new InputFilter[] {new NumericRangeFilter()};
   static final View.OnFocusChangeListener ON_FOCUS = new AmountOnFocusChangeListener();

Terakhir, di dalam onCreateView (...):

   EditText mAmountView = ....
   mAmountView.setFilters(FILTERS);
   mAmountView.setOnFocusChangeListener(ON_FOCUS);

Anda dapat menggunakan kembali FILTER dan ON_FOCUS pada sejumlah tampilan EditText.

Inilah kelas Utils:

public class Utils {

   private static final NumberFormat FORMAT_CURRENCY = NumberFormat.getCurrencyInstance();
   /** Parses an amount into cents.
    * @param p_value Amount formatted using the default currency. 
    * @return Value as cents.
    */
   public static int parseAmountToCents(String p_value) {
       try {
           Number v_value = FORMAT_CURRENCY.parse(p_value);
           BigDecimal v_bigDec = new BigDecimal(v_value.doubleValue());
           v_bigDec = v_bigDec.setScale(2, BigDecimal.ROUND_HALF_UP);
           return v_bigDec.movePointRight(2).intValue();
       } catch (ParseException p_ex) {
           try {
               // p_value doesn't have a currency format.
               BigDecimal v_bigDec = new BigDecimal(p_value);
               v_bigDec = v_bigDec.setScale(2, BigDecimal.ROUND_HALF_UP);
               return v_bigDec.movePointRight(2).intValue();
           } catch (NumberFormatException p_ex1) {
               return -1;
           }
       }
   }
   /** Formats cents into a valid amount using the default currency.
    * @param p_value Value as cents 
    * @return Amount formatted using a currency.
    */
   public static String formatCentsToAmount(int p_value) {
       BigDecimal v_bigDec = new BigDecimal(p_value);
       v_bigDec = v_bigDec.setScale(2, BigDecimal.ROUND_HALF_UP);
       v_bigDec = v_bigDec.movePointLeft(2);
       String v_currency = FORMAT_CURRENCY.format(v_bigDec.doubleValue());
       return v_currency.replace(FORMAT_CURRENCY.getCurrency().getSymbol(), "").replace(",", "");
   }
   /** Formats cents into a valid amount using the default currency.
    * @param p_value Value as cents 
    * @return Amount formatted using a currency.
    */
   public static String formatCentsToCurrency(int p_value) {
       BigDecimal v_bigDec = new BigDecimal(p_value);
       v_bigDec = v_bigDec.setScale(2, BigDecimal.ROUND_HALF_UP);
       v_bigDec = v_bigDec.movePointLeft(2);
       return FORMAT_CURRENCY.format(v_bigDec.doubleValue());
   }

}
miguelt
sumber
Meskipun ini secara teoritis dapat menjawab pertanyaan, kami ingin Anda memasukkan bagian penting dari artikel terkait dalam jawaban Anda, dan memberikan tautan untuk referensi . Gagal melakukan hal itu membuat jawaban berisiko mengalami pembusukan tautan.
Kev
Saya mendapatkan java.lang.NumberFormatException: Invalid double: "$ 12,345.00" saat teks edit kehilangan fokus. Bagaimana memperbaikinya.
Madhan
4

Saya menggunakan implementasi yang direferensikan oleh Nathan Leigh dan regex yang disarankan oleh Kayvan N dan user2582318 untuk menghapus semua karakter kecuali digit untuk membuat versi berikut:

fun EditText.addCurrencyFormatter() {

    // Reference: /programming/5107901/better-way-to-format-currency-input-edittext/29993290#29993290
    this.addTextChangedListener(object: TextWatcher {

        private var current = ""

        override fun afterTextChanged(s: Editable?) {
        }

        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
        }

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {

            if (s.toString() != current) {
                this@addCurrencyFormatter.removeTextChangedListener(this)
                // strip off the currency symbol

                // Reference for this replace regex: /programming/5107901/better-way-to-format-currency-input-edittext/28005836#28005836
                val cleanString = s.toString().replace("\\D".toRegex(), "")
                val parsed = if (cleanString.isBlank()) 0.0 else cleanString.toDouble()
                // format the double into a currency format
                val formated = NumberFormat.getCurrencyInstance()
                        .format(parsed / 100)

                current = formated
                this@addCurrencyFormatter.setText(formated)
                this@addCurrencyFormatter.setSelection(formated.length)

                this@addCurrencyFormatter.addTextChangedListener(this)
            }
        }
    })

}

Ini adalah fungsi ekstensi di Kotlin yang menambahkan TextWatcher ke TextChangedListener dari EditText.

Untuk menggunakannya, cukup:

yourEditText = (EditText) findViewById(R.id.edit_text_your_id);
yourEditText.addCurrencyFormatter()

Saya harap ini membantu.

Francisco Junior
sumber
3

Saya mendapatkan ini dari sini dan mengubahnya agar sesuai dengan format mata uang Portugis.

import java.text.NumberFormat;
import java.util.Currency;
import java.util.Locale;

import android.text.Editable;
import android.text.TextWatcher;
import android.widget.EditText;

public class CurrencyTextWatcher implements TextWatcher {

    private String current = "";
    private int index;
    private boolean deletingDecimalPoint;
    private final EditText currency;

    public CurrencyTextWatcher(EditText p_currency) {
        currency = p_currency;
    }


    @Override
    public void beforeTextChanged(CharSequence p_s, int p_start, int p_count, int p_after) {

        if (p_after>0) {
                index = p_s.length() - p_start;
            } else {
                index = p_s.length() - p_start - 1;
            }
            if (p_count>0 && p_s.charAt(p_start)==',') {
                deletingDecimalPoint = true;
            } else {
                deletingDecimalPoint = false;
            }

    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {

    }

    @Override
    public void afterTextChanged(Editable p_s) {


         if(!p_s.toString().equals(current)){
                currency.removeTextChangedListener(this);
                if (deletingDecimalPoint) {
                    p_s.delete(p_s.length()-index-1, p_s.length()-index);
                }
                // Currency char may be retrieved from  NumberFormat.getCurrencyInstance()
                String v_text = p_s.toString().replace("€","").replace(",", "");
                v_text = v_text.replaceAll("\\s", "");
                double v_value = 0;
                if (v_text!=null && v_text.length()>0) {
                    v_value = Double.parseDouble(v_text);
                }
                // Currency instance may be retrieved from a static member.
                NumberFormat numberFormat = NumberFormat.getCurrencyInstance(new Locale("pt", "PT"));
                String v_formattedValue = numberFormat.format((v_value/100));
                current = v_formattedValue;
                currency.setText(v_formattedValue);
                if (index>v_formattedValue.length()) {
                    currency.setSelection(v_formattedValue.length());
                } else {
                    currency.setSelection(v_formattedValue.length()-index);
                }
                // include here anything you may want to do after the formatting is completed.
                currency.addTextChangedListener(this);
             }
    }

}

Layout.xml

<EditText
    android:id="@+id/edit_text_your_id"
    ...
    android:text="0,00 €"
    android:inputType="numberDecimal"
    android:digits="0123456789" />

Dapatkan untuk bekerja

    yourEditText = (EditText) findViewById(R.id.edit_text_your_id);
    yourEditText.setRawInputType(Configuration.KEYBOARD_12KEY);
    yourEditText.addTextChangedListener(new CurrencyTextWatcher(yourEditText));
Nuno Monteiro
sumber
2

Bagi saya itu bekerja seperti ini

 public void onTextChanged(CharSequence s, int start,
                    int before, int count) {
                if(!s.toString().matches("^\\$(\\d{1,3}(\\,\\d{3})*|(\\d+))(\\.\\d{2})?$"))
                {
                    String userInput= ""+s.toString().replaceAll("[^\\d]", "");
                    if (userInput.length() > 2) {
                        Float in=Float.parseFloat(userInput);
                        price = Math.round(in); // just to get an Integer
                        //float percen = in/100;
                        String first, last;
                        first = userInput.substring(0, userInput.length()-2);
                        last = userInput.substring(userInput.length()-2);
                        edEx1.setText("$"+first+"."+last);
                        Log.e(MainActivity.class.toString(), "first: "+first + " last:"+last);
                        edEx1.setSelection(edEx1.getText().length());
                    }
                }
            }
Fernando
sumber
2

Lebih baik menggunakan antarmuka InputFilter. Jauh lebih mudah untuk menangani segala jenis input dengan menggunakan regex. Solusi saya untuk format masukan mata uang:

public class CurrencyFormatInputFilter implements InputFilter {

Pattern mPattern = Pattern.compile("(0|[1-9]+[0-9]*)(\\.[0-9]{1,2})?");

@Override
public CharSequence filter(
        CharSequence source,
        int start,
        int end,
        Spanned dest,
        int dstart,
        int dend) {

String result = 
        dest.subSequence(0, dstart)
        + source.toString() 
        + dest.subSequence(dend, dest.length());

Matcher matcher = mPattern.matcher(result);

if (!matcher.matches()) return dest.subSequence(dstart, dend);

return null;
}
}

Valid: 0.00, 0.0, 10.00, 111.1
Tidak valid: 0, 0.000, 111, 10, 010.00, 01.0

Cara Penggunaan:

editText.setFilters(new InputFilter[] {new CurrencyFormatInputFilter()});
Mussa
sumber
1

Jika bidang mata uang json Anda adalah tipe angka (dan bukan String) mungkin muncul sebagai 3.1, 3.15 atau hanya 3. Karena json secara otomatis membulatkan bidang angka.

Dalam hal ini Anda mungkin perlu membulatkannya untuk tampilan yang benar (dan untuk dapat menggunakan topeng pada bidang masukan nanti):

    NumberFormat nf = NumberFormat.getCurrencyInstance();

    float value = 200 // it can be 200, 200.3 or 200.37, BigDecimal will take care
    BigDecimal valueAsBD = BigDecimal.valueOf(value);
    valueAsBD.setScale(2, BigDecimal.ROUND_HALF_UP);

    String formated = nf.format(valueAsBD);

Mengapa ini dibutuhkan?

Semua jawaban menunjuk pada penghilangan simbol mata uang saat mengetik dengan menilai Anda menerima sen dan karenanya memformat dolar + cents / 100 = dolar, cents. Tetapi jika bidang mata uang json Anda adalah jenis angka (dan bukan String), itu akan membulatkan sen Anda, mungkin 3, 3.1 atau 3.15.

sagits
sumber
1
Persis yang saya butuhkan. Terima kasih!
Erick Engelhardt
come as 3.1 , 3.15 or just 3. Because json automatically round number fields- ini tidak umum dengan pembulatan !
Marcin Orlowski
1

pendekatan lain, tetapi berdasarkan jawaban Guilherme . Pendekatan ini berguna jika lokal negara Anda tidak tersedia, atau jika Anda ingin menggunakan simbol mata uang kustom. Penerapan ini hanya untuk non-desimal positif.

kode ini ada di Kotlin, delegasi pertama setMaskingMoneyuntukEditText

fun EditText.setMaskingMoney(currencyText: String) {
    this.addTextChangedListener(object: MyTextWatcher{
        val editTextWeakReference: WeakReference<EditText> = WeakReference<EditText>(this@setMaskingMoney)
        override fun afterTextChanged(editable: Editable?) {
            val editText = editTextWeakReference.get() ?: return
            val s = editable.toString()
            editText.removeTextChangedListener(this)
            val cleanString = s.replace("[Rp,. ]".toRegex(), "")
            val newval = currencyText + cleanString.monetize()

            editText.setText(newval)
            editText.setSelection(newval.length)
            editText.addTextChangedListener(this)
        }
    })
}

Kemudian MyTextWatcherantarmuka harus diperpanjang dari TextWatcher. Karena kita hanya membutuhkan afterTextChangedmetode, metode lain perlu menggantikan antarmuka ini

interface MyTextWatcher: TextWatcher {
    override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
    override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
}

dan metode monetisasi adalah:

fun String.monetize(): String = if (this.isEmpty()) "0"
    else DecimalFormat("#,###").format(this.replace("[^\\d]".toRegex(),"").toLong())

Implementasi penuh:

fun EditText.setMaskingMoney(currencyText: String) {
    this.addTextChangedListener(object: MyTextWatcher{
        val editTextWeakReference: WeakReference<EditText> = WeakReference<EditText>(this@setMaskingMoney)
        override fun afterTextChanged(editable: Editable?) {
            val editText = editTextWeakReference.get() ?: return
            val s = editable.toString()
            editText.removeTextChangedListener(this)
            val cleanString = s.replace("[Rp,. ]".toRegex(), "")
            val newval = currencyText + cleanString.monetize()

            editText.setText(newval)
            editText.setSelection(newval.length)
            editText.addTextChangedListener(this)
        }
    })
}

interface MyTextWatcher: TextWatcher {
    override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
    override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
}


fun String.monetize(): String = if (this.isEmpty()) "0"
    else DecimalFormat("#,###").format(this.replace("[^\\d]".toRegex(),"").toLong())

dan di suatu tempat di metode onCreate:

yourTextView.setMaskingMoney("Rp. ")
Hayi Nukman
sumber
1

Setelah terlalu banyak pencarian dan gagal dengan Doubles, BigDecimals dan sebagainya, saya telah membuat kode ini. Ia bekerja plug And Play. Di kotlin. Jadi, untuk membantu orang lain yang kesulitan seperti saya, ayo pergi.

Kode pada dasarnya adalah fungsi yang akan menempatkan textWatcher dan menyesuaikan koma ke tempat yang tepat.

Pertama, buat fungsi ini:

fun CurrencyWatcher( editText:EditText) {

    editText.addTextChangedListener(object : TextWatcher {
        //this will prevent the loop
        var changed: Boolean = false

        override fun afterTextChanged(p0: Editable?) {
            changed = false

        }

        override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {

            editText.setSelection(p0.toString().length)
        }

        @SuppressLint("SetTextI18n")
        override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
            if (!changed) {
                changed = true

                var str: String = p0.toString().replace(",", "").trim()
                var element0: String = str.elementAt(0).toString()
                var element1: String = "x"
                var element2: String = "x"
                var element3: String = "x"
                var element4: String = "x"
                var element5: String = "x"
                var element6: String = "x"

                //this variables will store each elements of the initials data for the case we need to move this numbers like: 0,01 to 0,11 or 0,11 to 0,01
                if (str.length >= 2) {
                    element1 = str.elementAt(1).toString()
                }
                if (str.length >= 3) {
                    element2 = str.elementAt(2).toString()
                }

                editText.removeTextChangedListener(this)


                //this first block of code will take care of the case
                //where the number starts with 0 and needs to adjusta the 0 and the "," place
                if (str.length == 1) {
                    str = "0,0" + str
                    editText.setText(str)

                } else if (str.length <= 3 && str == "00") {

                    str = "0,00"
                    editText.setText(str)
                    editText.setSelection(str.length)
                } else if (element0 == "0" && element1 == "0" && element2 == "0") {
                    str = str.replace("000", "")
                    str = "0,0" + str
                    editText.setText(str)
                } else if (element0 == "0" && element1 == "0" && element2 != "0") {
                    str = str.replace("00", "")
                    str = "0," + str
                    editText.setText(str)
                } else {

                    //This block of code works with the cases that we need to move the "," only because the value is bigger
                    //lets get the others elements
                    if (str.length >= 4) {
                        element3 = str.elementAt(3).toString()
                    }
                    if (str.length >= 5) {
                        element4 = str.elementAt(4).toString()
                    }
                    if (str.length >= 6) {
                        element5 = str.elementAt(5).toString()
                    }
                    if (str.length == 7) {
                        element6 = str.elementAt(6).toString()
                    }


                    if (str.length >= 4 && element0 != "0") {

                        val sb: StringBuilder = StringBuilder(str)
                        //set the coma in right place
                        sb.insert(str.length - 2, ",")
                        str = sb.toString()
                    }

                    //change the 0,11 to 1,11
                    if (str.length == 4 && element0 == "0") {

                        val sb: StringBuilder = StringBuilder(str)
                        //takes the initial 0 out
                        sb.deleteCharAt(0);
                        str = sb.toString()

                        val sb2: StringBuilder = StringBuilder(str)
                        sb2.insert(str.length - 2, ",")
                        str = sb2.toString()
                    }

                    //this will came up when its like 11,11 and the user delete one, so it will be now 1,11
                    if (str.length == 3 && element0 != "0") {
                        val sb: StringBuilder = StringBuilder(str)
                        sb.insert(str.length - 2, ",")
                        str = sb.toString()
                    }

                    //came up when its like 0,11 and the user delete one, output will be 0,01
                    if (str.length == 2 && element0 == "0") {
                        val sb: StringBuilder = StringBuilder(str)
                        //takes 0 out
                        sb.deleteCharAt(0);
                        str = sb.toString()

                        str = "0,0" + str

                    }

                    //came up when its 1,11 and the user delete, output will be 0,11
                    if (str.length == 2 && element0 != "0") {
                        val sb: StringBuilder = StringBuilder(str)
                        //retira o 0 da frente
                        sb.insert(0, "0,")
                        str = sb.toString()

                    }


                    editText.setText(str)
                }

                //places the selector at the end to increment the number
                editText.setSelection(str.length)
                editText.addTextChangedListener(this)
            }

        }
    })
}

Dan kemudian Anda memanggil fungsi ini dengan cara ini

val etVal:EditText = findViewById(R.id.etValue)

CurrencyWatcher(etVal)
Thiago Silva
sumber
0

Setelah melihat sebagian besar posting StackOverflow pada cara-cara yang berbeda untuk mencapai ini menggunakan TextWatcher, InputFilteratau perpustakaan seperti CurrencyEditText aku menetap di solusi sederhana ini menggunakanOnFocusChangeListener .

Logikanya adalah mengurai EditTextmenjadi angka saat difokuskan dan memformatnya kembali saat kehilangan fokus.

amount.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(View view, boolean hasFocus) {
            Number numberAmount = 0f;
            try {
                numberAmount = Float.valueOf(amount.getText().toString());
            } catch (NumberFormatException e1) {
                e1.printStackTrace();
                try {
                    numberAmount = NumberFormat.getCurrencyInstance().parse(amount.getText().toString());
                } catch (ParseException e2) {
                    e2.printStackTrace();
                }
            }
            if (hasFocus) {
                amount.setText(numberAmount.toString());
            } else {
                amount.setText(NumberFormat.getCurrencyInstance().format(numberAmount));
            }
        }
    });
Abtin Gramian
sumber
0

Saya telah menerapkan versi Kotlin + Rx.

Ini untuk mata uang Brasil (mis. 1.500.00 - 5,21 - 192,90) tetapi Anda dapat dengan mudah menyesuaikan untuk format lain.

Semoga orang lain merasa terbantu.

RxTextView
            .textChangeEvents(fuel_price) // Observe text event changes
            .filter { it.text().isNotEmpty() } // do not accept empty text when event first fires
            .flatMap {
                val onlyNumbers = Regex("\\d+").findAll(it.text()).fold(""){ acc:String,it:MatchResult -> acc.plus(it.value)}
                Observable.just(onlyNumbers)
            }
            .distinctUntilChanged()
            .map { it.trimStart('0') }
            .map { when (it.length) {
                        1-> "00"+it
                        2-> "0"+it
                        else -> it }
            }
            .subscribe {
                val digitList = it.reversed().mapIndexed { i, c ->
                    if ( i == 2 ) "${c},"
                    else if ( i < 2 ) c
                    else if ( (i-2)%3==0 ) "${c}." else c
                }

                val currency = digitList.reversed().fold(""){ acc,it -> acc.toString().plus(it) }
                fuel_price.text = SpannableStringBuilder(currency)
                fuel_price.setSelection(currency.length)
            }
Vinicius Lima
sumber
0

CurrencyTextWatcher.java

public class CurrencyTextWatcher implements TextWatcher {

    private final static String DS = "."; //Decimal Separator
    private final static String TS = ","; //Thousands Separator
    private final static String NUMBERS = "0123456789"; //Numbers
    private final static int MAX_LENGTH = 13; //Maximum Length

    private String format;

    private DecimalFormat decimalFormat;
    private EditText editText;

    public CurrencyTextWatcher(EditText editText) {
        String pattern = "###" + TS + "###" + DS + "##";
        decimalFormat = new DecimalFormat(pattern);
        this.editText = editText;
        this.editText.setInputType(InputType.TYPE_CLASS_NUMBER);
        this.editText.setKeyListener(DigitsKeyListener.getInstance(NUMBERS + DS));
        this.editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(MAX_LENGTH)});
    }

    @Override
    public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

    }

    @Override
    public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {

    }

    @Override
    public void afterTextChanged(Editable editable) {

        editText.removeTextChangedListener(this);
        String value = editable.toString();
        if (!value.isEmpty()) {
            value = value.replace(TS, "");
            try {
                format = decimalFormat.format(Double.parseDouble(value));
                format = format.replace("0", "");
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }

            editText.setText(format);
        }

        editText.addTextChangedListener(this);
    }
}

EditTextCurrency.java

public class EditTextCurrency extends AppCompatEditText {
    public EditTextCurrency(Context context) {
        super(context);
    }

    public EditTextCurrency(Context context, AttributeSet attrs) {
        super(context, attrs);
        addTextChangedListener(new CurrencyTextWatcher(this));
    }
}

masukkan deskripsi gambar di sini

Samet ÖZTOPRAK
sumber
0

Berikut adalah bagaimana saya dapat menampilkan mata uang dalam EditText yang mudah diterapkan dan bekerja dengan baik untuk pengguna tanpa potensi simbol gila di semua tempat. Ini tidak akan mencoba melakukan pemformatan apa pun hingga EditText tidak lagi memiliki fokus. Pengguna tetap dapat kembali dan mengedit tanpa merusak pemformatan. Saya menggunakan variabel 'formattedPrice' untuk tampilan saja, dan variabel 'itemPrice' sebagai nilai yang saya simpan / gunakan untuk penghitungan.

Tampaknya ini bekerja dengan sangat baik, tetapi saya baru melakukannya selama beberapa minggu, jadi kritik yang membangun sangat diterima!

Tampilan EditText di xml memiliki atribut berikut:

android:inputType="numberDecimal"

Variabel global:

private String formattedPrice;
private int itemPrice = 0;

Dalam metode onCreate:

EditText itemPriceInput = findViewById(R.id.item_field_price);

itemPriceInput.setOnFocusChangeListener(new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        String priceString = itemPriceInput.getText().toString();

        if (! priceString.equals("")) {
            itemPrice = Double.parseDouble(priceString.replaceAll("[$,]", ""));
            formattedPrice = NumberFormat.getCurrencyInstance().format(itemPrice);
            itemPriceInput.setText(formattedPrice);
        }
    }
});
Kat
sumber
0

Jika seseorang tertarik dengan cara melakukannya menggunakan RxBinding dan Kotlin:

var isEditing = false

RxTextView.textChanges(dollarValue)
            .filter { !isEditing }
            .filter { it.isNotBlank() }
            .map { it.toString().filter { it.isDigit() } }
            .map { BigDecimal(it).setScale(2, BigDecimal.ROUND_FLOOR).divide(100.toBigDecimal(), BigDecimal.ROUND_FLOOR) }
            .map { NumberFormat.getCurrencyInstance(Locale("pt", "BR")).format(it) }
            .subscribe {
                isEditing = true
                dollarValue.text = SpannableStringBuilder(it)
                dollarValue.setSelection(it.length)
                isEditing = false
            }
Guilherme V.
sumber
0

hanya komentar tambahan untuk jawaban yang disetujui. Anda mungkin mengalami crash saat memindahkan kursor pada bidang teks editan karena penguraian. Saya melakukan pernyataan coba tangkap, tetapi menerapkan kode Anda sendiri.

@Override public void onTextChanged(CharSequence s, int start, int before, int count) {
        if(!s.toString().equals(current)){
        amountEditText.removeTextChangedListener(this);

            String cleanString = s.toString().replaceAll("[$,.]", "");

            try{
                double parsed = Double.parseDouble(cleanString);
                String formatted = NumberFormat.getCurrencyInstance().format((parsed/100));
                current = formatted;
                amountEditText.setText(formatted);
                amountEditText.setSelection(formatted.length());
            } catch (Exception e) {

            }

            amountEditText.addTextChangedListener(this);
        }
    }
Andrew Trang
sumber
0

Anda dapat menggunakan metode ini

import android.text.Editable
import android.text.TextWatcher
import android.widget.EditText
import android.widget.TextView
import java.text.NumberFormat
import java.util.*

fun TextView.currencyFormat() {
    addTextChangedListener(object : TextWatcher {
        override fun afterTextChanged(s: Editable?) {}

        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
            removeTextChangedListener(this)
            text = if (s?.toString().isNullOrBlank()) {
                ""
            } else {
                s.toString().currencyFormat()
            }
            if(this@currencyFormat is EditText){
                setSelection(text.toString().length)
            }
            addTextChangedListener(this)
        }
    })
}

fun String.currencyFormat(): String {
    var current = this
    if (current.isEmpty()) current = "0"
    return try {
        if (current.contains('.')) {
            NumberFormat.getNumberInstance(Locale.getDefault()).format(current.replace(",", "").toDouble())
        } else {
            NumberFormat.getNumberInstance(Locale.getDefault()).format(current.replace(",", "").toLong())
        }
    } catch (e: Exception) {
        "0"
    }
}
Kourosh
sumber
0

Versi Kotlin :

    var current = ""

    editText.addTextChangedListener(object: TextWatcher {
        override fun afterTextChanged(s: Editable?) {}
        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
            val stringText = s.toString()

            if(stringText != current) {
                editText.removeTextChangedListener(this)

                val locale: Locale = Locale.UK
                val currency = Currency.getInstance(locale)
                val cleanString = stringText.replace("[${currency.symbol},.]".toRegex(), "")
                val parsed = cleanString.toDouble()
                val formatted = NumberFormat.getCurrencyInstance(locale).format(parsed / 100)

                current = formatted
                editText.setText(formatted)
                editText.setSelection(formatted.length)
                editText.addTextChangedListener(this)
            }
        }
    })
Adriatik Gashi
sumber
0
public class MoneyEditText extends android.support.v7.widget.AppCompatEditText{
public MoneyEditText(Context context) {
    super(context);
    addTextChangedListener(MoneySplitter());
}
public MoneyEditText(Context context, AttributeSet attrs) {
    super(context, attrs);
    addTextChangedListener(MoneySplitter());
}
public MoneyEditText(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    addTextChangedListener(MoneySplitter());
}
public TextWatcher MoneySplitter() {
    TextWatcher textWatcher = new TextWatcher() {
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            try
            {
                removeTextChangedListener(this);
                String value = s.toString();
                if (!value.equals(""))
                {
                        if(!TextUtils.isEmpty(value))
                            setText(formatPrice(Double.parseDouble(value)));
                        setSelection(getText().toString().length());

                }
                addTextChangedListener(this);
            }
            catch (Exception ex)
            {
                ex.printStackTrace();
                addTextChangedListener(this);
            }
        }
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        }
        @Override
        public void afterTextChanged(Editable s) {
        }
    };
    return textWatcher;
}

public static String formatPrice(double value){
        int DecimalPointNumber = 2;
        Locale locale = Locale.getDefault();
        DecimalFormat myFormatter = (DecimalFormat) NumberFormat.getCurrencyInstance(locale);
        StringBuilder sb = new StringBuilder();
        if(DecimalPointNumber>0){
            for (int i = 0; i < DecimalPointNumber; i++) {
                sb.append("#");
            }
            myFormatter.applyPattern("###,###."+ sb.toString());
        }else
            myFormatter.applyPattern("###,###"+ sb.toString());

            return Currency.getInstance(Locale.getDefault()).getSymbol() + myFormatter.format(value);
    }
}

dan kemudian gunakan blok ini sebagai editText Anda

   <MoneyEditText
   android:id="@+id/txtPrice"
   android:layout_width="match_parent"
   android:layout_height="64dp"
   android:digits="0123456789.,"
   android:inputType="numberDecimal"
   android:selectAllOnFocus="true"
   android:singleLine="true" />
Saeid Mohammadi
sumber
Anda dapat menggunakan teks edit yang disesuaikan ini untuk memformat teks input seperti yang Anda inginkan.
Saeid Mohammadi
Saya mengubah kelas ini untuk menerima bilangan negatif. Kode di bawah sebagai jawaban.
Michel Fernandes
0

Ini seperti jawaban Saeid Mohammadi tetapi saya berubah untuk menerima angka negatif.

  package com.example.liberdade.util
    
    import android.text.Editable
    import android.text.TextWatcher
    import android.widget.EditText
    import java.lang.ref.WeakReference
    import java.math.BigDecimal
    import java.text.NumberFormat
    import java.util.*
    
    
    class MoneyTextWatcher : TextWatcher {
    
    
    
        private val editTextWeakReference: WeakReference<EditText?>?
        private val locale: Locale = Locale("pt", "BR")
        //private final Locale locale;
    
        constructor(editText: EditText?, locale: Locale?) {
            editTextWeakReference = WeakReference<EditText?>(editText)
            //this.locale = if (locale != null) locale else Locale.getDefault()
        }
    
        constructor(editText: EditText?) {
            editTextWeakReference = WeakReference<EditText?>(editText)
            //locale = Locale.getDefault()
        }
    
        override fun beforeTextChanged(
            s: CharSequence?,
            start: Int,
            count: Int,
            after: Int
        ) {
        }
    
        override fun onTextChanged(
            s: CharSequence?,
            start: Int,
            before: Int,
            count: Int
        ) {
        }
    
        override fun afterTextChanged(editable: Editable?) {
            val editText: EditText = editTextWeakReference?.get() ?: return
            editText.removeTextChangedListener(this)
    
            var isNegative = false
            var editableString = editable.toString()
            if (editable != null) {
                if (editableString.contains('-')) {
                    isNegative = true
                    if (editable != null) {
                        editableString = editableString.replace("-","")
                    }
                }
            }
    
            val parsed: BigDecimal? = parseToBigDecimal(editableString, locale)
            //val parsed: BigDecimal? = parseToBigDecimal(editable.toString(), locale)
            var formatted: String = NumberFormat.getCurrencyInstance(locale).format(parsed)
    
            if (isNegative && !(formatted.equals("R\$ 0,00") || formatted.equals("-R\$ 0,00"))) formatted = "-${formatted}"
            editText.setText(formatted)
            editText.setSelection(formatted.length)
            editText.addTextChangedListener(this)
        }
    
        private fun parseToBigDecimal(value: String?, locale: Locale?): BigDecimal? {
            val replaceable = java.lang.String.format(
                "[%s,.\\s]",
                NumberFormat.getCurrencyInstance(locale).currency.symbol
            )
            val cleanString = value!!.replace(replaceable.toRegex(), "")
            return BigDecimal(cleanString).setScale(
                2, BigDecimal.ROUND_FLOOR
            ).divide(
                BigDecimal(100), BigDecimal.ROUND_FLOOR
            )
        }
    }
    
    //como invocar
    //binding.editTextValorCaixa.addTextChangedListener(MoneyTextWatcher(binding.editTextValorCaixa, Locale("pt", "BR")))
Michel Fernandes
sumber