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
setText
method inside theafterTextChanged
method. CallingsetText
is obviously changing the text which causesafterTextChanged
to be called again. This results in theafterTextChanged
being 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
EditText
and override theonSelectionChanged
method.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() > 0
is to ensure that theEditText
contains 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
filter
method, thedest
parameter represents theEditText
's text, and thedstart
anddend
parameters 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 ifdstart
is 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 hiddenEditText
contain the raw input from the user, and having theTextView
on top of theEditText
. You would use aTextWatcher
to update theTextView
with the properly formatted input from theEditText
.