1
votes

I'm trying to display an EditText with decimal values, however I'm having trouble with phones set to English language. I need this EditText to use comma as the decimal separator, but Android keyboard does not have a feature to localize the decimal separator. So I'm using the following code and it is not working.

import java.text.DecimalFormat;
import java.text.ParseException;

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

public class NumberTextWatcher implements TextWatcher {

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

    private EditText et;

    public NumberTextWatcher(EditText et)
    {
    Locale locale  = new Locale("pt", "BR");
    df = (DecimalFormat) NumberFormat.getNumberInstance(locale);
    DecimalFormatSymbols.getInstance().setDecimalSeparator(',');
    DecimalFormatSymbols.getInstance().setGroupingSeparator('.');

    // THE ERROR HAPPENS IN THE NEXT LINE
    df.applyPattern("#.###,##");

    df.setDecimalSeparatorAlwaysShown(true);
    dfnd = (DecimalFormat) NumberFormat.getNumberInstance(locale);
    dfnd.applyPattern("#.###");
    this.et = et;
    hasFractionalPart = false;
    }

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

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

    @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().contains(String.valueOf(df.getDecimalFormatSymbols().getDecimalSeparator())))
        {
        hasFractionalPart = true;
        } else {
        hasFractionalPart = false;
    }
    }

}

Here is the exception:

10-26 16:59:23.100  16231-16231/com.br.myapp.debug E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.br.myapp.debug, PID: 16231
    java.lang.IllegalArgumentException: syntax error: DecimalFormat::applyPattern failed: U_UNEXPECTED_TOKEN: #.###,##
            at libcore.icu.NativeDecimalFormat.applyPattern(NativeDecimalFormat.java:490)
            at libcore.icu.NativeDecimalFormat.applyPattern(NativeDecimalFormat.java:278)
            at java.text.DecimalFormat.applyPattern(DecimalFormat.java:589)
            at com.br.myapp.util.NumberTextWatcher.(NumberTextWatcher.java:27)
            at com.br.myapp.fragments.PriceDialogFragment.onCreateDialog(PriceDialogFragment.java:73)
            at android.support.v4.app.DialogFragment.getLayoutInflater(DialogFragment.java:307)
            at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:942)
            at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1121)
            at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
            at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1484)
            at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:450)
            at android.os.Handler.handleCallback(Handler.java:733)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:146)
            at android.app.ActivityThread.main(ActivityThread.java:5679)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1291)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1107)
            at dalvik.system.NativeStart.main(Native Method)
1
Please post something relevant here instead of just link. For example you may include expected outputs. This will ensure more peoples' interest and you are likely to get more answers quickly - Nabin

1 Answers

1
votes

Problem solved using the code below. It's not a generic code, but may help other people.

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


public class NumberTextWatcher implements TextWatcher {

    private EditText mEditText;

    public NumberTextWatcher(EditText editText) {
        mEditText = editText;
    }

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

    }

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

    }

    @Override
    public void afterTextChanged(Editable editable) {
        mEditText.removeTextChangedListener(this);

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

            String v = editable.toString().replace(".", ",");

            // Se começar com vírgula, acrescento o zero automaticamente
            if (inilen == 1 && v.equals(",")) {
                v = "0,";
            }

            // Se já tiver vírgula, não deixo inserir novamente
            if (v.indexOf(",") != v.lastIndexOf(",")) {
                if (v.lastIndexOf(",") == v.length() - 1) {
                    v = v.substring(0, v.length() - 1);
                }
            }

            // Se já tiver vírgula, não deixo ficar com 3 dígitos na parte decimal
            int separatorPosition = v.indexOf(",");
            String decimalPart = v.substring(separatorPosition + 1);
            if (decimalPart.length() > 2) {
                v = v.substring(0, v.length() - 1);
            }

            int cp = mEditText.getSelectionStart();
            mEditText.setText(v);
            endlen = mEditText.getText().length();

            int sel = (cp + (endlen - inilen));
            if (sel > 0 && sel <= mEditText.getText().length()) {
                mEditText.setSelection(sel);
            } else {
                if (mEditText.getText().length() > 0) {
                    // place cursor at the end?
                    mEditText.setSelection(mEditText.getText().length() - 1);
                }
            }
        } catch (NumberFormatException nfe) {
            // do nothing?
        }

        mEditText.addTextChangedListener(this);
    }
}