Bessere Möglichkeit zur Formatierung von Währungseingabe editText?

Ich habe einen editText, Startwert ist $ 0.00. Wenn Sie 1 drücken, ändert sich der Wert auf 0,01. Drücken Sie 4, es geht auf 0,14 $. Drücke 8, $ 1.48. Drücken Sie die Rücktaste, $ 0,14, usw.

Das Problem ist, wenn jemand den Cursor manuell positioniert, treten Probleme bei der Formatierung auf. Wenn sie die Dezimalzahl löschen, wird sie nicht zurückkommen. Wenn sie den Cursor vor den Dezimalpunkt stellen und 2 eingeben, wird $ 02.00 statt $ 2.00 angezeigt. Wenn sie versuchen, das $ zu löschen, wird stattdessen beispielsweise eine Ziffer gelöscht.

Hier ist der Code, den ich verwende, ich würde mich über Vorschläge freuen.

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

   

Ich habe Ihre Methode getestet, aber es schlägt fehl, wenn ich große Zahlen verwende … Ich habe Folgendes erstellt:

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

Basierend auf einigen der obigen Antworten habe ich einen MoneyTextWatcher erstellt, den Sie wie folgt verwenden würden:

 priceEditText.addTextChangedListener(new MoneyTextWatcher(priceEditText)); 

und hier ist die class:

 public class MoneyTextWatcher implements TextWatcher { private final WeakReference editTextWeakReference; public MoneyTextWatcher(EditText editText) { editTextWeakReference = new WeakReference(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); } } 

Tatsächlich funktioniert die zuvor bereitgestellte Lösung nicht. Es funktioniert nicht, wenn Sie 100,00 eingeben möchten.

Ersetzen:

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

Mit:

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

Ich muss sagen, dass ich einige Änderungen für meinen Code vorgenommen habe. Die Sache ist, dass Sie BigDecimal verwenden sollten

Hier ist meine benutzerdefinierte 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 
*
  • Always use locale US instead of default to make DecimalFormat work well in all language
  • */ 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
    * + When focus EditText, set the default text = prefix (ex: VND)
    * + 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); } } } }

    Verwenden Sie es in XML wie

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

    Sie sollten 2 Konstante unten passend für Ihr Projekt bearbeiten

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

    Bildbeschreibung hier eingeben

    Demo auf GitHub

    Ich ändere die class mit implementiertem TextWatcher, um brasilianische Währungsformate zu verwenden und die Cursorposition bei der Bearbeitung des Wertes anzupassen.

     Öffentliche class MoneyTextWatcher implementiert TextWatcher {
    
         privater EditText editText;
    
         private String lastAmount = "";
    
         private int lastCursorPosition = -1;
    
         öffentliche MoneyTextWatcher (EditText editText) {
             Super();
             this.editText = editText;
         }
    
         @Override
         public void onTextChanged (CharSequence-Menge, int start, int vor, int count) {
    
             if (! amount.toString (). ist gleich (lastAmount)) {
    
                 Zeichenfolge cleanString = clearCurrencyToNumber (amount.toString ());
    
                 Versuchen {
    
                     Zeichenfolge formatiertAmount = transformToCurrency (cleanString);
                     editText.removeTextChangedListener (this);
                     editText.setText (formatiertAmount);
                     editText.setSelection (formatierteAmount.length ());
                     editText.addTextChangedListener (this);
    
                     if (lastCursorPosition! = lastAmount.length () && lastCursorPosition! = -1) {
                         int lengthDelta = formatiertAmount.length () - lastAmount.length ();
                         int newCursorOffset = max (0, min (formatedAmount.length (), lastCursorPosition + lengthDelta));
                         editText.setSelection (newCursorOffset);
                     }
                 } catch (Ausnahme e) {
                    // melde etwas
                 }
             }
         }
    
         @Override
         public void afterTextChanged (Bearbeitbare s) {
         }
    
         @Override
         public void beforeTextChanged (Zeichenkette s, int start, int count, int after) {
             Zeichenfolgenwert = s.toString ();
             if (! value.equals ("")) {
                 String cleanString = clearCurrencyToNumber (Wert);
                 Zeichenfolge formatiertAmount = transformToCurrency (cleanString);
                 lastAmount = formatiertAmount;
                 lastCursorPosition = editText.getSelectionStart ();
             }
         }
    
         public static Zeichenfolge clearCurrencyToNumber (String currencyValue) {
             String Ergebnis = null;
    
             if (currencyValue == null) {
                 Ergebnis = "";
             } sonst {
                 Ergebnis = currencyValue.replaceAll ("[(az) | (AZ) | ($.)]", "");
             }
             Ergebnis zurückgeben;
         }
    
         public static boolean isCurrencyValue (String currencyValue, boolean podeSerZero) {
             boolesches Ergebnis;
    
             if (currencyValue == null || currencyValue.length () == 0) {
                 Ergebnis = falsch;
             } sonst {
                 if (! podeSerZero && currencyValue.equals ("0,00")) {
                     Ergebnis = falsch;
                 } sonst {
                     Ergebnis = wahr;
                 }
             }
             Ergebnis zurückgeben;
         }
    
         public static Zeichenfolge transformToCurrency (String value) {
             doppelt geparst = Double.parseDouble (Wert);
             String formatiert = NumberFormat.getCurrencyInstance (neues Gebietsschema ("pt", "BR")). Format ((parsed / 100));
             formatiert = formatiert.replaceAll ("[^ (0-9) (.,)]", "");
             return formatiert;
         }
     }
    

    Ich baute auf Guilhermes Antwort, aber ich behalte die Position des Cursors und behandeln Sie die Perioden auch anders – auf diese Weise, wenn ein Benutzer nach dem Punkt eingibt, hat es keinen Einfluss auf die Zahlen vor dem Zeitraum, finde ich, dass dies eine sehr glatte Eingabe gibt .

      [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) { } }); 

    Ok, hier ist ein besserer Weg, mit Währungsformaten umzugehen, Löschen-Zurück-Tastenanschlag. Der Code basiert auf @androidcurious ‘Code oben … Aber, befasst sich mit einigen Problemen im Zusammenhang mit Rückwärts-Löschung und einigen Parse-Ausnahmen: http://miguelt.blogspot.ca/2013/01/textwatcher-for-currency-masksformatting .html [UPDATE] Die vorherige Lösung hatte einige Probleme … Dies ist eine bessere Lösung: http://miguelt.blogspot.ca/2013/02/update-textwatcher-for-currency.html Und … hier sind die Einzelheiten:

    Dieser Ansatz ist besser, da er die herkömmlichen Android-Mechanismen verwendet. Die Idee besteht darin, Werte zu formatieren, nachdem der Benutzer die Ansicht existiert.

    Definieren Sie einen InputFilter, um die numerischen Werte einzuschränken. Dies ist in den meisten Fällen erforderlich, da der Bildschirm nicht groß genug für lange EditText-Ansichten ist. Dies kann eine statische innere class oder nur eine andere einfache class sein:

     /** 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 ""; } } 

    Definieren Sie eine class (innere statische class oder nur eine class), die View.OnFocusChangeListener implementiert. Beachten Sie, dass ich eine Utils-class verwende – die Implementierung kann unter “Beträge, Steuern” gefunden werden.

     /** 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); } } } 

    Diese class entfernt das Währungsformat bei der Bearbeitung – basierend auf Standardmechanismen. Wenn der Benutzer beendet wird, wird das Währungsformat erneut angewendet.

    Es ist besser, einige statische Variablen zu definieren, um die Anzahl der Instanzen zu minimieren:

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

    Schließlich, innerhalb der onCreateView (…):

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

    Sie können FILTERS und ON_FOCUS für beliebig viele EditText-Ansichten wiederverwenden.

    Hier ist die Utils-class:

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

    Für mich hat es so funktioniert

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

    Es ist besser, die InputFilter-Schnittstelle zu verwenden. Viel einfacher zu handhaben jede Art von Eingaben mit Hilfe von Regex. Meine Lösung für das Währungseingabeformat:

     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; } } 

    Gültig: 0.00, 0.0, 10.00, 111.1
    Ungültig: 0, 0.000, 111, 10, 010.00, 01.0

    Wie benutzt man:

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

    Auch wenn es hier viele Antworten gibt, möchte ich diesen Code, den ich hier gefunden habe, teilen, da ich glaube, dass er die robusteste und sauberste Antwort ist.

     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) { } } 

    ich hoffe es hilft.

    Ich habe das von hier und änderte es, um dem portugiesischen Währungsformat zu entsprechen.

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

    Die layout.xml

      

    Lass es funktionieren

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

    Ich benutzte dies, um dem Benutzer zu erlauben, die Währung einzugeben und sie von Zeichenkette in int zu konvertieren, um in db zu speichern und wieder von int in Zeichenkette zu wechseln

    https://github.com/nleigh/Restaurant/blob/master/Restaurant/src/de/co/nathanleigh/restaurant/CurrencyFormat.java

    Wenn Ihr JSON-Währungsfeld vom Zahlentyp (und nicht von String) ist, kann es 3,1, 3,15 oder nur 3 sein. Weil json automatisch runde Zahlenfelder erzeugt.

    In diesem Fall müssen Sie es eventuell runden, damit es korrekt angezeigt wird (und später eine Maske in einem Eingabefeld verwenden können):

      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); 

    Warum ist das nötig?

    Alle Antworten zeigen auf das Entfernen von Währungssimbolen, wenn Sie beim Tippen tippen, Sie erhalten die Cents und bilden so dolar + cents / 100 = dolar, cents. Aber wenn Ihr JSON-Währungsfeld ein Zahlentyp (und kein String) ist, wird es Ihre Cent, es kann 3, 3.1 oder 3.15 sein.

    Ich habe die Implementierung Nathan Leigh referenziert und Kayvan N’s und user2582318 s vorgeschlagenen Regex alle Zeichen außer Ziffern zu entfernen, um die folgende Version zu erstellen:

     fun EditText.addCurrencyFormatter() { // Reference: https://stackoverflow.com/questions/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: https://stackoverflow.com/questions/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) } } }) } 

    Dies ist eine Erweiterungsfunktion in Kotlin, die den TextWatcher zum TextChangedListener des EditText hinzufügt.

    Um es zu benutzen, nur:

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

    Ich hoffe, es hilft.

    Nachdem ich die meisten StackOverflow-Posts auf verschiedene Arten betrachtet habe, um dies mit einem TextWatcher , InputFilter oder einer Bibliothek wie CurrencyEditText zu erreichen, habe ich mich für diese einfache Lösung mit einem OnFocusChangeListener .

    Die Logik besteht darin, den EditText auf eine Zahl zu analysieren, wenn er fokussiert ist, und ihn zu formatieren, wenn er den Fokus verliert.

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

    Ich habe eine Kotlin + Rx-Version implementiert.

    Es ist für brasilianische Währung (zB 1.500,00 – 5,21 – 192,90), aber Sie können leicht für andere Formate anpassen.

    Hoffe, jemand anderes findet es hilfreich.

     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) } 

    ein anderer Ansatz, aber basierend auf Guilherme Antwort . Dieser Ansatz ist nützlich, wenn das Gebietsschema Ihres Landes nicht verfügbar ist oder wenn Sie benutzerdefinierte Währungssymbole verwenden möchten. Diese Implementierung ist nur für positive nicht-dezimale.

    Dieser Code ist in Kotlin, erster Delegierter setMaskingMoney für EditText

     fun EditText.setMaskingMoney(currencyText: String) { this.addTextChangedListener(object: MyTextWatcher{ val editTextWeakReference: WeakReference = WeakReference(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) } }) } 

    Dann sollte die MyTextWatcher Schnittstelle von TextWatcher erweitert TextWatcher . Da wir nur die afterTextChanged Methode benötigen, müssen die anderen Methoden in dieser Schnittstelle übersteuert werden

     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) {} } 

    und die Monetarisierungsmethoden sind:

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

    Vollständige Implementierungen:

     fun EditText.setMaskingMoney(currencyText: String) { this.addTextChangedListener(object: MyTextWatcher{ val editTextWeakReference: WeakReference = WeakReference(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()) 

    and somewhere on onCreate method:

     yourTextView.setMaskingMoney("Rp. ") 

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

    Bildbeschreibung hier eingeben

    Here is how I was able to display a currency in an EditText that was easy to implement and works well for the user without the potential for crazy symbols all over the place. This will not try to do any formatting until the EditText no longer has focus. The user can still go back and make any edits without jeopardizing the formatting. I use the ‘formattedPrice’ variable for display only, and the ‘itemPrice’ variable as the value that I store/use for calculations.

    It seems to be working really well, but I’ve only been at this for a few weeks, so any constructive criticism is absolutely welcome!

    The EditText view in the xml has the following attribute:

     android:inputType="numberDecimal" 

    Global variables:

     private String formattedPrice; private int itemPrice = 0; 

    In the onCreate method:

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

    In case someone is interested in a way of doing it using RxBinding and 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 } 

    just an additional comment to the approved answer. You may get a crash when moving the cursor on edittext field due to parsing. I did a try catch statement, but implement your own code.

     @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); } }