13

How do you create an edittext entry that formats input in money format only? When the user enters 5, I want the input to look like "$0.05" and when they then enter 3, the input should now look like "$0.53" and finally they enter 6 and the input should look like "$5.36".

miannelle
  • 2,241
  • 5
  • 20
  • 15

7 Answers7

8

ninjasense's complete solution basically works, but it has some issues:

  1. Every time the data of the field is altered in the "onTextChanged" handler, cursor position resets to index 0 on the field, which is a bit annoying to happen when typing in monetary values.
  2. It uses floats for formatting monetary values, which can backfire.

For the first problem I don't have solution yet, for the second one code like this works:

    @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]", "");
            StringBuilder cashAmountBuilder = new StringBuilder(userInput);

            while (cashAmountBuilder.length() > 3 && cashAmountBuilder.charAt(0) == '0') {
                cashAmountBuilder.deleteCharAt(0);
            }
            while (cashAmountBuilder.length() < 3) {
                cashAmountBuilder.insert(0, '0');
            }
            cashAmountBuilder.insert(cashAmountBuilder.length()-2, '.');
            cashAmountBuilder.insert(0, '$');

            cashAmountEdit.setText(cashAmountBuilder.toString());
        }

    }
Zds
  • 4,311
  • 2
  • 24
  • 28
3

Building off Zds.

For keeping the cursor positioned at the end of the field use this.

cashAmountEdit.setTextKeepState(cashAmountBuilder.toString());
Selection.setSelection(cashAmountEdit.getText(), cashAmountBuilder.toString().length());
rozsnyai
  • 31
  • 1
1

You can use a TextWatcher to do that kind of thing.

Extend TextWatcher: http://d.android.com/reference/android/text/TextWatcher.html

public class MyTextWatcher implements TextWatcher {

    public void afterTextChanged(Editable arg0) { 

    }

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

    }

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

    }

}

Then add it to your editText with

myEditText.addTextChangedListener(new MyTextWatcher());
m6tt
  • 4,223
  • 1
  • 22
  • 20
1

I found the TextWatcher to be a bit cumbersome. Instead, you can set the key listener:

setKeyListener(new CalculatorKeyListener());
// Must be called after setKeyListener(), otherwise is overridden
setRawInputType(Configuration.KEYBOARD_12KEY);

And then create a KeyListener which extends NumberKeyListener:

class CalculatorKeyListener extends NumberKeyListener {
    @Override
    public int getInputType() {
        return InputType.TYPE_CLASS_NUMBER;
    }

    @Override
    public boolean onKeyDown(View view, Editable content, int keyCode, KeyEvent event) {
        if (keyCode >= KeyEvent.KEYCODE_0 && keyCode <= KeyEvent.KEYCODE_9) {
            digitPressed(keyCode - KeyEvent.KEYCODE_0);
        } else if (keyCode == KeyEvent.KEYCODE_DEL) {                                         
            deletePressed();
        }
        return true;
    }

    @Override
    protected char[] getAcceptedChars() {
        return new char[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    }
}

You then need to display the characters correctly, but that's not difficult; just keep track of cents, and then divide or multiply by 10, and use a NumberFormat to get the formatting correct.

Shawn Lauzon
  • 6,234
  • 4
  • 35
  • 46
  • 2
    KeyListener is no longer working on some devices, see this note: Key presses on soft input methods are not required to trigger the methods in this listener, and are in fact discouraged to do so. The default android keyboard will not trigger these for any key to any application targetting Jelly Bean or later, and will only deliver it for some key presses to applications targetting Ice Cream Sandwich or earlier. Source: http://developer.android.com/reference/android/text/method/KeyListener.html – Dan Osipov Sep 10 '12 at 18:34
1

Heres my complete solution:

                tvValue.setRawInputType(Configuration.KEYBOARD_12KEY);

            tvValue.addTextChangedListener(new TextWatcher(){


                @Override
                public void afterTextChanged(Editable arg0) {
                    // TODO Auto-generated method stub

                }

                @Override
                public void beforeTextChanged(CharSequence s, int start,
                        int count, int after) {
                    // TODO Auto-generated method stub

                }

                @Override
                public void onTextChanged(CharSequence s, int start,
                        int before, int count) {
                    // TODO Auto-generated method stub

                    // here i converted to string
                    if(!s.toString().matches("^\\$(\\d{1,3}(\\,\\d{3})*|(\\d+))(\\.\\d{2})?$"))
                    {
                        String userInput= ""+s.toString().replaceAll("[^\\d]", "");
                        Float in=Float.parseFloat(userInput);
                        float percen = in/100;
                        tvValue.setText("$"+percen);
                    }

                }

            });
ninjasense
  • 13,756
  • 19
  • 75
  • 92
0

I did this but without decimal and with dot for miles, check the code and add the functionality to support decimals.

    MyEditText.addTextChangedListener(new TextWatcher() 
        {
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count){
                if(s.toString().length() > 0){
                    MyEditText.removeTextChangedListener(this);                 
                    String numbers = removeCharacters(s.toString());
                    int money = 0;
                    try{
                        money = Integer.parseInt(numbers);
                    }
                    catch(Exception ex){
                        money = 0;
                    }

                    MyEditText.setText(getMoney(money));
                    //Set cursor on correct position
                    int selection = start;
                    if(count > 0){
                        selection++;
                        if(MyEditText.getText().toString().length() == 2 || MyEditText.getText().toString().length() == 6 || MyEditText.getText().toString().length() == 10){
                            selection++;
                        }                           
                    }
                    else{
                        if(MyEditText.getText().toString().length() == 4 || MyEditText.getText().toString().length() == 8){
                            selection--;
                        }
                    }

                    if(selection > MyEditText.getText().toString().length()){
                        selection = MyEditText.getText().toString().length();
                    }                       

                    MyEditText.setSelection(selection);
                    MyEditText.addTextChangedListener(this);
                }
                if(s.toString().length() == 1 && count < 1 && start == 1){
                    MyEditText.removeTextChangedListener(this);
                    MyEditText.setText("");
                    MyEditText.addTextChangedListener(this);
                }

            }           

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

            }           

            @Override
            public void afterTextChanged(Editable s) 
            {

            }

        });



    public String removeCharacters(String money){       

    int i=0;
    while (i<money.length())
    {
        Character c = money.charAt(i);          
            if (Character.isDigit(c) && c != '.')
            {               
                i++;
            }
            else
            {               
                money = money.replace(c.toString(), "");                
            }
    }

    return money;
}


public String getMoney(int value){
    String money = "$";
    NumberFormat numberFormatter;       
    numberFormatter = NumberFormat.getNumberInstance(Locale.GERMAN);        
    money += numberFormatter.format(value);

    return money;
}
Sergio Ramirez
  • 680
  • 5
  • 7
0

This answer is based on Zds' answer (which in turn was based on ninjasense's answer), but this should resolve the cursor position issue:

if(!text.matches("^\\$(\\d{1,2})(\\.\\d{2})?$")) {
    int originalCursorPosition = view.getSelectionStart();
    int cursorOffset = 0;

    boolean cursorAtEnd = originalCursorPosition == text.length();

    String userInput= ""+text.replaceAll("[^\\d]", "");
    StringBuilder cashAmountBuilder = new StringBuilder(userInput);

    while (cashAmountBuilder.length() > 3 && cashAmountBuilder.charAt(0) == '0')           {  
        cashAmountBuilder.deleteCharAt(0);
        cursorOffset--;
    }
    while (cashAmountBuilder.length() < 3) {
        cashAmountBuilder.insert(0, '0');
        cursorOffset++;
    }
    cashAmountBuilder.insert(cashAmountBuilder.length() - 2, '.');
    cashAmountBuilder.insert(0, '$');

    view.setText(cashAmountBuilder.toString());
    view.setSelection(cursorAtEnd ? view.getText().length() : originalCursorPosition + cursorOffset);
}

Notes:

  • The following is in a TextWatcher.onTextChanged
  • I'm using a different regex than other answers, which keeps the price to < $100
  • 'view' is the editText, 'text' is the string contents
  • this has worked for me using an EditText with a maxLength of 6 (i.e. $00.00)
Community
  • 1
  • 1
Squimon
  • 581
  • 5
  • 7