I have a text field where the start symbol is $ (could be euro or pound depending on an application setting). I need to make it so that if the user clicks before the symbol nothing will happen. In other words, the selection must remain after the symbol. I tried doing something like this but it seems wrong and it gave me an error:
billAmount.addTextChangedListener(new TextWatcher() {
//other methods
@Override
public void afterTextChanged(Editable s) {
billAmount.setText(currencySymbol + billAmount.getText().toString());
}
});
I was thinking of using an inputFilter but nothing I tried worked. I'm also not allowed to use a TextView right before the EditText.
First, in your code sample, the reason you are getting an error is because, as others have said, you are calling the
setTextmethod inside theafterTextChangedmethod. CallingsetTextis obviously changing the text which causesafterTextChangedto be called again. This results in theafterTextChangedbeing called continuously until there is eventually a stack overflow.You have two issues: 1) You want to always keep the cursor positioned after the currency symbol, and 2) You want to make sure the currency symbol is never somehow removed.
The easiest way to solve #1 is to create a subclass of
EditTextand override theonSelectionChangedmethod.This will force the cursor to always go after the currency symbol even if the user attempts to move it before it. The check
getText().length() > 0is to ensure that theEditTextcontains at least one character, otherwise attempting to move the cursor will result in an Exception.As for #2, there are a couple ways to go at it. You can attempt to use some instance variables inside your TextWatcher to keep track of when the text needs to be formatted, but that won't prevent the unnecessary method calls from actually happening, and it adds some unneeded complexity. I think it would be easier to simply use an
InputFilter, which you can specify in your extended EditText's constructor.In the
filtermethod, thedestparameter represents theEditText's text, and thedstartanddendparameters represent the start and end positions of the portion of the text that is about to be replaced. Since the currency symbol should always be the first character, we know it is about to be replaced ifdstartis zero, in which case we simply return thesource(which represents the replacement text) with the currency symbol placed in front. Otherwise, we indicate that the change is okay by returningnull.I tested it, and it seems to work for what you need.
On a side note, although I understand that you're not "allowed" to use a
TextView, I think it's worth reiterating that using one would provide a much better solution to this problem. One particularly useful solution being to have a hiddenEditTextcontain the raw input from the user, and having theTextViewon top of theEditText. You would use aTextWatcherto update theTextViewwith the properly formatted input from theEditText.