Mejor manera de formato de entrada de moneda editText?

Tengo un editText, el valor inicial es $ 0.00. Al presionar 1, cambia a $ 0.01. Presione 4, va a $ 0.14. Pulse 8, $ 1.48. Presione retroceso, $ 0.14, etc.

Eso funciona, el problema es que si alguien coloca el cursor manualmente, se producen problemas en el formateo. Si eliminaran el decimal, no volverán. Si colocan el cursor delante del decimal y escriben 2, mostrarán $ 02.00 en lugar de $ 2.00. Si intentan borrar el $ borrará un dígito en su lugar, por ejemplo.

Aquí está el código que estoy usando, agradecería cualquier sugerencia.

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

He probado su método, pero falla cuando uso grandes números … He creado esto:

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

Sobre la base de algunas de las respuestas anteriores creé un MoneyTextWatcher que utilizaría de la siguiente manera:

 priceEditText.addTextChangedListener(new MoneyTextWatcher(priceEditText)); 

Y aquí está la clase:

 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(); editText.removeTextChangedListener(this); String cleanString = s.toString().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); } } 

En realidad, la solución provista anteriormente no funciona. No funciona si quieres ingresar 100.00.

Reemplazar:

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

Con:

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

Debo decir que he hecho algunas modificaciones para mi código. La cosa es que usted debe utilizar BigDecimal

Cambie la clase con implementa TextWatcher para usar los formatos de moneda de Brasil y ajustar la posición del cursor al editar el valor.

 Public class MoneyTextWatcher implementa TextWatcher {

     Private EditarTexto editarTexto;

     Private String lastAmount = "";

     Private int lastCursorPosition = -1;

     Public MoneyTextWatcher (EditText editText) {
         súper();
         This.editText = editText;
     }

     @Anular
     Public void onTextChanged (cantidad de CharSequence, int start, int before, int count) {

         If (! Amount.toString (). Iguales (lastAmount)) {

             Cadena cleanString = clearCurrencyToNumber (amount.toString ());

             tratar {

                 Cadena formattedAmount = transformToCurrency (cleanString);
                 EditText.removeTextChangedListener (este);
                 EditText.setText (formattedAmount);
                 EditText.setSelection (formattedAmount.length ());
                 EditText.addTextChangedListener (this);

                 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 (Excepción e) {
                // registrar algo
             }
         }
     }

     @Anular
     Public void afterTextChanged (Editable s) {
     }

     @Anular
     Public void beforeTextChanged (CharSequence s, int inicio, int count, int after) {
         String value = s.toString ();
         If (! Value.equals ("")) {
             String cleanString = clearCurrencyToNumber (valor);
             Cadena formattedAmount = transformToCurrency (cleanString);
             LastAmount = formattedAmount;
             LastCursorPosition = editText.getSelectionStart ();
         }
     }

     Public static String clearCurrencyToNumber (String currencyValue) {
         String result = null;

         If (currencyValue == null) {
             Resultado = "";
         } Else {
             Resultado = currencyValue.replaceAll ("[(az) | (AZ) | ($ ,.)]", "");
         }
         Resultado de retorno;
     }

     Public static boolean isCurrencyValue (String currencyValue, boolean podeSerZero) {
         Resultado booleano;

         If (currencyValue == null || currencyValue.length () == 0) {
             Resultado = falso;
         } Else {
             If (! PodeSerZero && currencyValue.equals ("0,00")) {
                 Resultado = falso;
             } Else {
                 Resultado = verdadero;
             }
         }
         Resultado de retorno;
     }

     Public static String transformToCurrency (Valor de cadena) {
         Double parsed = Double.parseDouble (valor);
         String formatted = NumberFormat.getCurrencyInstance (new Locale ("pt", "BR")). Formato ((analizado / 100));
         Formatted = formatted.replaceAll ("[^ (0-9) (.,)]", "");
         Return formatted;
     }
 }

He construido sobre la respuesta de Guilhermes, pero conservo la posición del cursor y también tratar los períodos de manera diferente – de esta manera si un usuario está escribiendo después del período, no afecta a los números antes del período que encuentro que esto da una entrada muy suave .

  [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, aquí está una mejor manera de tratar con los formatos de moneda, borrar-pulsar hacia atrás. El código está basado en el código @androidcurious '… Pero, trata algunos problemas relacionados con la eliminación hacia atrás y algunas excepciones de análisis: http://miguelt.blogspot.ca/2013/01/textwatcher-for-currency-masksformatting .html [UPDATE] La solución anterior tenía algunos problemas … Esta es una solución mejor: http://miguelt.blogspot.ca/2013/02/update-textwatcher-for-currency.html Y … aquí están los Detalles

Este enfoque es mejor ya que utiliza los mecanismos convencionales de Android. La idea es dar formato a valores después de que el usuario exista la vista.

Definir un InputFilter para restringir los valores numéricos – esto es necesario en la mayoría de los casos porque la pantalla no es lo suficientemente grande para acomodar largas vistas de EditText. Esto puede ser una clase interna estática o simplemente otra clase simple:

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

Defina una clase (interna estática o simplemente una clase) que implementará View.OnFocusChangeListener. Tenga en cuenta que estoy usando una clase Utils – la implementación se puede encontrar en "Importe, Impuestos".

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

Esta clase eliminará el formato de moneda al editar – dependiendo de los mecanismos estándar. Cuando el usuario sale, se vuelve a aplicar el formato de moneda.

Es mejor definir algunas variables estáticas para minimizar el número de instancias:

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

Finalmente, dentro de onCreateView (…):

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

Puede volver a utilizar FILTERS y ON_FOCUS en cualquier número de vistas de EditText.

Aquí está la clase Utils:

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

Para mí funcionó de esta manera

  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 mejor usar la interfaz de InputFilter. Mucho más fácil de manejar cualquier tipo de entradas usando regex. Mi solución para el formato de entrada de moneda:

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

Válido: 0,00, 0,0, 10,00, 111,1
No válido: 0, 0,000, 111, 10, 010,00, 01,0

Cómo utilizar:

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

Aunque hay muchas respuestas aquí, me gustaría compartir este código que he encontrado aquí ya que creo que es la respuesta más sólida y limpia.

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

Espero eso ayude.

Conseguí esto de aquí y lo cambié para cumplir con el formato de la modernidad portuguesa.

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

El layout.xml

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

Hazlo funcionar

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

Si su campo de moneda json es de tipo numérico (y no de cadena) puede llegar como 3.1, 3.15 o sólo 3. Debido a que json automáticamente redondea los campos numéricos.

En este caso, es posible que tenga que redondearla para mostrar correctamente (y poder usar una máscara en un campo de entrada más adelante):

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

¿Por qué es necesario?

Todas las respuestas apuntan a la eliminación de simbolos de divisas al escribir juzgando que está recibiendo los centavos y por lo que formatear dolar + centavos / 100 = dolar, centavos. Pero si su campo de moneda de json es un tipo de número (y no una cadena) redondeará sus centavos, puede ser 3, 3.1 o 3.15.

Aquí está mi personalizado CurrencyEditText

 import android.content.Context; import android.graphics.Rect; import android.text.Editable; import android.text.InputType; import android.text.TextWatcher; import android.util.AttributeSet; import android.widget.EditText; import java.math.BigDecimal; import java.text.DecimalFormat; public class CurrencyEditText extends android.support.v7.widget.AppCompatEditText { private static String prefix = "VND "; private static final int MAX_DECIMAL = 3; private CurrencyTextWatcher mCurrencyTextWatcher = 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); } private static class CurrencyTextWatcher implements TextWatcher { private final EditText mEditText; private String prevString; private String prefix; CurrencyTextWatcher(EditText editText, String prefix) { mEditText = editText; this.prefix = prefix; } @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) { String str = editable.toString(); if (str.length() < prefix.length()) { mEditText.setText(prefix); mEditText.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(prevString) || cleanString.isEmpty()) { return; } prevString = cleanString; String formattedString; if (cleanString.contains(".")) { formattedString = formatDecimal(cleanString); } else { formattedString = formatInteger(cleanString); } mEditText.setText(formattedString); mEditText.setSelection(formattedString.length()); } private String formatInteger(String str) { BigDecimal parsed = new BigDecimal(str); DecimalFormat formatter; formatter = new DecimalFormat(prefix + "#,###"); return formatter.format(parsed); } private String formatDecimal(String str) { if (str.equals(".")) { return prefix + "."; } BigDecimal parsed = new BigDecimal(str); DecimalFormat formatter; // example patter VND #,###.00 formatter = new DecimalFormat(prefix + "#,###." + getDecimalPattern(str)); 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() - 1 - str.indexOf("."); String decimalPattern = ""; for (int i = 0; i < decimalCount && i < MAX_DECIMAL; i++) { decimalPattern += "0"; } return decimalPattern; } } @Override protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { super.onFocusChanged(focused, direction, previouslyFocusedRect); if (focused) { this.addTextChangedListener(mCurrencyTextWatcher); if (getText().toString().isEmpty()) { setText(prefix); } } else { this.removeTextChangedListener(mCurrencyTextWatcher); if (getText().toString().equals(prefix)) { setText(""); } } } } 

Utilícelo en XML como

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

Debe editar 2 constantes a continuación para que sean adecuadas para su proyecto

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

Introduzca aquí la descripción de la imagen

Demo en github

Utilicé esto para permitir al usuario entrar en la moneda y convertirlo de cadena en int para almacenar en db y cambiar de nuevo de int en cadena de nuevo

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

Después de mirar la mayoría de los mensajes de StackOverflow en diferentes formas de lograr esto utilizando un TextWatcher , InputFilter o una biblioteca como CurrencyEditText he establecido en esta solución simple con un OnFocusChangeListener .

La lógica es analizar el EditText a un número cuando está enfocado y darle formato de nuevo cuando pierde el foco.

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

He implementado una versión de Kotlin + Rx.

Es para la moneda brasileña (por ejemplo, 1,500.00 – 5,21 – 192,90), pero se puede adaptar fácilmente para otros formatos.

Espero que alguien lo encuentre útil.

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

Otro enfoque, pero basado en la respuesta Guilherme . Este enfoque es útil cuando la configuración regional de su país no está disponible o si desea utilizar símbolos de moneda personalizados. Esta implementación es sólo para positivos no decimales.

Este código está en Kotlin, el primer delegado setMaskingMoney para EditText

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

A MyTextWatcher interfaz MyTextWatcher debe extenderse desde TextWatcher . Dado que sólo necesitamos el método afterTextChanged , los otros métodos necesitan superponerse en esta interfaz

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

Y los métodos de monetización son:

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

Implementaciones completas:

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

Y en algún lugar del método onCreate:

 yourTextView.setMaskingMoney("Rp. ") 
FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.