Saltar al contenido

Cómo formatear el número en Android EditText después de la edición en tiempo real

Ya no busques más por otros sitios ya que has llegado al sitio exacto, contamos con la solución que buscas sin complicarte.

Solución:

Esta clase resuelve el problema, permite la entrada decimal y suma los separadores de miles.

    public class NumberTextWatcher implements TextWatcher 

    private DecimalFormat df;
    private DecimalFormat dfnd;
    private boolean hasFractionalPart;

    private EditText et;

    public NumberTextWatcher(EditText et)
    
        df = new DecimalFormat("#,###.##");
        df.setDecimalSeparatorAlwaysShown(true);
        dfnd = new DecimalFormat("#,###");
        this.et = et;
        hasFractionalPart = false;
    

    @SuppressWarnings("unused")
    private static final String TAG = "NumberTextWatcher";

    public void afterTextChanged(Editable s)
    
        et.removeTextChangedListener(this);

        try 
            int inilen, endlen;
            inilen = et.getText().length();

            String v = s.toString().replace(String.valueOf(df.getDecimalFormatSymbols().getGroupingSeparator()), "");
            Number n = df.parse(v);
            int cp = et.getSelectionStart();
            if (hasFractionalPart) 
                et.setText(df.format(n));
             else 
                et.setText(dfnd.format(n));
            
            endlen = et.getText().length();
            int sel = (cp + (endlen - inilen));
            if (sel > 0 && sel <= et.getText().length()) 
                et.setSelection(sel);
             else 
                // place cursor at the end?
                et.setSelection(et.getText().length() - 1);
            
         catch (NumberFormatException nfe) 
            // do nothing?
         catch (ParseException e) 
            // do nothing?
        

        et.addTextChangedListener(this);
    

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

    public void onTextChanged(CharSequence s, int start, int before, int count)
    
        if (s.toString().contains(String.valueOf(df.getDecimalFormatSymbols().getDecimalSeparator())))
        
            hasFractionalPart = true;
         else 
            hasFractionalPart = false;
        
    


Fuente: http://blog.roshka.com/2012/08/android-edittext-with-number-format.html

Desafortunadamente, el código no funcionó como está en la respuesta.

Tiene dos problemas:

  1. No funciona si la configuración regional del teléfono utiliza "," como separador decimal.
  2. No funciona si el número tiene ceros al final de la parte decimal. Ejemplo 1.01.

Me volví loco por arreglarlo. Finalmente llegué a este código que funcionó bien en mi teléfono celular:

NumberTextWatcher.java

import android.text.Editable;
import android.text.TextWatcher;
import android.text.method.DigitsKeyListener;
import android.util.Log;
import android.widget.EditText;

import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.ParseException;
import java.util.Locale;


public class NumberTextWatcher
        implements TextWatcher 

    private static final String TAG = "NumberTextWatcher";

    private final int numDecimals;
    private String groupingSep;
    private String decimalSep;
    private boolean nonUsFormat;
    private DecimalFormat df;
    private DecimalFormat dfnd;
    private boolean hasFractionalPart;

    private EditText et;
    private String value;


    private String replicate(char ch, int n) 
        return new String(new char[n]).replace("", "" + ch);
    

    public NumberTextWatcher(EditText et, Locale locale, int numDecimals) 

        et.setKeyListener(DigitsKeyListener.getInstance("0123456789.,"));
        this.numDecimals = numDecimals;
        DecimalFormatSymbols symbols = new DecimalFormatSymbols(locale);

        char gs = symbols.getGroupingSeparator();
        char ds = symbols.getDecimalSeparator();
        groupingSep = String.valueOf(gs);
        decimalSep = String.valueOf(ds);

        String patternInt = "#,###";
        dfnd = new DecimalFormat(patternInt, symbols);

        String patternDec = patternInt + "." + replicate('#', numDecimals);
        df = new DecimalFormat(patternDec, symbols);
        df.setDecimalSeparatorAlwaysShown(true);
        df.setRoundingMode(RoundingMode.DOWN);

        this.et = et;
        hasFractionalPart = false;

        nonUsFormat = !decimalSep.equals(".");
        value = null;

    


    @Override
    public void afterTextChanged(Editable s) 
        Log.d(TAG, "afterTextChanged");
        et.removeTextChangedListener(this);

        try 
            int inilen, endlen;
            inilen = et.getText().length();

            String v = value.replace(groupingSep, "");

            Number n = df.parse(v);

            int cp = et.getSelectionStart();
            if (hasFractionalPart) 
                int decPos = v.indexOf(decimalSep) + 1;
                int decLen = v.length() - decPos;
                if (decLen > numDecimals) 
                    v = v.substring(0, decPos + numDecimals);
                
                int trz = countTrailingZeros(v);

                StringBuilder fmt = new StringBuilder(df.format(n));
                while (trz-- > 0) 
                    fmt.append("0");
                
                et.setText(fmt.toString());
             else 
                et.setText(dfnd.format(n));
            


            endlen = et.getText().length();
            int sel = (cp + (endlen - inilen));
            if (sel > 0 && sel <= et.getText().length()) 
                et.setSelection(sel);
             else 
                // place cursor at the end?
                et.setSelection(et.getText().length() - 1);
            


         catch (NumberFormatException 

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) 
        Log.d(TAG, "beforeTextChanged");
        value = et.getText().toString();
    

    private int countTrailingZeros(String str) 
        int count = 0;

        for (int i = str.length() - 1; i >= 0; i--) 
            char ch = str.charAt(i);
            if ('0' == ch) 
                count++;
             else 
                break;
            
        
        return count;
    

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) 
        Log.d(TAG, "onTextChanged");

        String newValue = s.toString();
        String change = newValue.substring(start, start + count);
        String prefix = value.substring(0, start);
        String suffix = value.substring(start + before);

        if (".".equals(change) && nonUsFormat) 
            change = decimalSep;
        

        value = prefix + change + suffix;
        hasFractionalPart = value.contains(decimalSep);

        Log.d(TAG, "VALUE: " + value);


    


y luego usarlo simplemente para hacer:

    Locale locale = new Locale("es", "AR"); // For example Argentina
    int numDecs = 2; // Let's use 2 decimals
    TextWatcher tw = new NumberTextWatcher(myEditText, locale, numDecs);
    myEditText.addTextChangedListener(tw);

Necesitas usar DecimalFormat clase con DecimalFormatSymbols clase, echa un vistazo al siguiente método,

public static String formatAmount(int num) 

    DecimalFormat decimalFormat = new DecimalFormat();
    DecimalFormatSymbols decimalFormateSymbol = new DecimalFormatSymbols();
    decimalFormateSymbol.setGroupingSeparator(',');
    decimalFormat.setDecimalFormatSymbols(decimalFormateSymbol);
    return decimalFormat.format(num);

Te mostramos comentarios y valoraciones

Nos puedes corroborar nuestra función exponiendo un comentario y puntuándolo te lo agradecemos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *