TextWatcher not detecting delete key - java

I have a TextWatcher that places a percent sign after numbers in an EditText. That part works fine. The problem is if the user makes a mistake and needs to delete the numbers in the editText, the percent sign does not allow any deletions. below is my code:
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
editText.removeTextChangedListener(this);
try {
String originalString = s.toString();
if (originalString.contains("%")) {
originalString = originalString.replaceAll("%", "");
}
String formattedString = originalString + "%";
//setting text after format to EditText
editText.setText(formattedString);
editText.setSelection(editText.getText().length());
} catch (NumberFormatException nfe) {
nfe.printStackTrace();
}
editText.addTextChangedListener(this);
}
I believe I need an OnKeyListener but don't know exactly how to implement it. this is what I did with the OnKeyListener but it doesn't work:
boolean keyDelete
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
if(!keyDelete) {
editText.removeTextChangedListener(this);
try {
String originalString = s.toString();
if (originalString.contains("%")) {
originalString = originalString.replaceAll("%", "");
}
String formattedString = originalString + "%";
//setting text after format to EditText
editText.setText(formattedString);
editText.setSelection(editText.getText().length());
} catch (NumberFormatException nfe) {
nfe.printStackTrace();
}
editText.addTextChangedListener(this);
}
}
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DEL){
keyDelete = true;
}else{
keyDelete = false;
}
return false;
}
Any help on this is greatly appreciated..

Your code works fine if a user sets a cursor before '%' symbol. The issue is that after text formatting you set selection to the end of a text.
editText.setSelection(editText.getText().length());
In a case, when a user pushes the delete button without replacing a cursor, he is deleting '%' symbol, but your code returns '%' symbol back each time. This is because feels like:
the percent sign does not allow any deletions
To solve your issue refactor your code to set selections before '%' symbol:
#Override
public void afterTextChanged(Editable s) {
editText.removeTextChangedListener(this);
try {
String originalString = s.toString();
if (originalString.contains("%")) {
originalString = originalString.replaceAll("%", "");
}
String formattedString = originalString + "%";
//setting text after format to EditText
editText.setText(formattedString);
if (formattedString.length() >= 1) {
editText.setSelection(editText.getText().length() - 1);
}
} catch (NumberFormatException nfe) {
nfe.printStackTrace();
}
editText.addTextChangedListener(this);
}

Related

Convert formatCurrency (rupiah) to int

Here I have a method like this:
// method currency format
private String formatRupiah(Double number) {
Locale locale = new Locale("IND", "ID");
NumberFormat numberFormat = NumberFormat.getCurrencyInstance(locale);
String formatRupiah = numberFormat.format(number);
String[] split = formatRupiah.split(",");
int length = split[0].length();
String formatRupiahString = split[0].substring(0, 2) + " " + split[0].substring(2, length);
return formatRupiahString;
}
And also have this method to change the text that is in the edit text into the currency format:
private void editTextToFormatCurrency() {
etJumlah.addTextChangedListener(new TextWatcher() {
private String jumlahFormat = Objects.requireNonNull(etJumlah.getText()).toString().trim();
#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().equals(jumlahFormat)) {
etJumlah.removeTextChangedListener(this);
String replace = s.toString().replaceAll("[Rp. ]", "");
if (!replace.isEmpty()) {
jumlahFormat = formatRupiah(Double.parseDouble(replace));
} else {
jumlahFormat = "";
}
etJumlah.setText(jumlahFormat);
etJumlah.setSelection(jumlahFormat.length());
etJumlah.addTextChangedListener(this);
}
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
And now my question is how to change TextToFormatCurrencycto int or Integer without format currency ?
My goal of changing back to Integer or int is so I can upload to Firestore with data type number.
And the answer:
https://www.youtube.com/watch?v=TdgQW8T-KeQ&t (this is my video)
https://www.youtube.com/watch?v=NQOK2cam3js&t (this is my inspiration video)
String jumlahString = Objects.requireNonNull(String.valueOf(layoutJumlah.getEditText().getText()));
jumlahString = jumlahString.replaceAll("[^0-9]", "");
jumlah = Integer.parseInt(jumlahString);

How to add 3 decimal places Currency formatting to edittext Using TextWatcher Android

I want to add 3 decimal places currency formatting to EditText using TextWatcher
at the beginning, value is 0.000 and the number should change right to left
eg: if I pressed 1,2,3,4,5 in order value should appear as this 12.345
following code is worked only for 2 decimal places. Please anyone helps me how to change this code for 3 decimal places or another solution
public class CurrencyTextWatcher implements TextWatcher {
boolean mEditing;
Context context;
public CurrencyTextWatcher() {
mEditing = false;
}
public synchronized void afterTextChanged(Editable s) {
if(!mEditing) {
mEditing = true;
String digits = s.toString().replaceAll("\\D", "");
NumberFormat nf = NumberFormat.getCurrencyInstance();
try{
String formatted = nf.format(Double.parseDouble(digits)/100);
s.replace(0, s.length(), formatted);
} catch (NumberFormatException nfe) {
s.clear();
}
mEditing = false;
}
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
public void onTextChanged(CharSequence s, int start, int before, int count) { }
}
Divide 1000 instead of 100 and also setMinimumFractionDigits for NumberFormat as 3.
public class CurrencyTextWatcher implements TextWatcher {
boolean mEditing;
Context context;
public CurrencyTextWatcher() {
mEditing = false;
}
public synchronized void afterTextChanged(Editable s) {
if(!mEditing) {
mEditing = true;
String digits = s.toString().replaceAll("\\D", "");
NumberFormat nf = NumberFormat.getCurrencyInstance();
nf.setMinimumFractionDigits(3);
try{
String formatted = nf.format(Double.parseDouble(digits)/1000);
s.replace(0, s.length(), formatted);
} catch (NumberFormatException nfe) {
s.clear();
}
mEditing = false;
}
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
public void onTextChanged(CharSequence s, int start, int before, int count) { }
}

'equals()' between objects of inconvertible types 'int' and 'TextWatcher' error

i have a strange error that i can't solve. The error is : 'equals()' between objects of inconvertible types 'int' and 'TextWatcher'. And this is my code:
if( textWatcher_ans.equals(R.string.editText_7)){
Toast.makeText(getApplication().getBaseContext(),
(R.string.Good),Toast.LENGTH_SHORT).show();
}
private final TextWatcher textWatcher_ans = new TextWatcher(){
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
textView_name.setVisibility(View.VISIBLE);
}
public void afterTextChanged(Editable s) {
if (s.length() == 0) {
textView_name.setVisibility(View.GONE);
} else {
textView_name.setText("You have entered : " + editText_surname.getText());
}
}
I'm pretty stuck and i dont know what to do.
can someone pleas help me?
If your aim is to display the R.string.Good message if the text in editText_surname matches R.string.editText_7 then try something like this:
First attach the TextWatcher to editText_surname:
editText_surname.addTextChangedListener(textWatcher_ans);
In your afterTextChangedMethod:
public void afterTextChanged(Editable s) {
if (s.length() == 0) {
textView_name.setVisibility(View.GONE);
} else {
textView_name.setText("You have entered : " + s.toString());
}
if (s.toString().equals(context.getString(R.string.editText_7)) {
Toast.makeText(getApplication().getBaseContext(),
(R.string.Good),Toast.LENGTH_SHORT).show();
}
}

EditText CurrencyFormat without symbol Android

The code below produce an stackoverflow error. The idea is to format the amount when or after user type an amount.
500 -> 500.00
1000 -> 1 000.00
29999.55-> 29 999.55
..
..
..
edit_amount.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
#Override
public void afterTextChanged(Editable s) {
if (edit_amount.getText().toString().length()>0){
edit_amount.setText(
currencyFormat(edit_amount.getText().toString()));
}else {}
}
});
public String currencyFormat(String number){
String credits="";
try {
//en, us
if (TextUtils.isEmpty(MyApplication.pref.GetPreferences("AppCurrency"))){
credits = NumberFormat.getCurrencyInstance(new Locale("fr", "FR")).format(Double.valueOf(number));
}else {
if (MyApplication.pref.GetPreferences("AppCurrency").equals("Euro")) {
credits = NumberFormat.getCurrencyInstance(new Locale("fr", "FR")).format(Double.valueOf(number));
} else {
credits = NumberFormat.getCurrencyInstance(new Locale("en", "US")).format(Double.valueOf(number));
}
}
}catch(Exception ex){
credits = "mCredits";
}
return credits;
}
Your code doesn't work because when you call edit_amount.setText(...) then the afterTextChanged(Editable s) is triggered and then edit_amount.setText(...) is triggered and so on. You need to change your logic to do what you want and avoid stack overflow.
For example you could unregister TextWatcher, setText and then register it again.
Alternatively, you can set a flag so that your TextWatcher knows when you change the text yourself and then instruct TextWatcher to ignore it.
To avoid recursive invocation of afterTextChanged callback you can set up additional chek. Smth like this
#Override
public void afterTextChanged(Editable s) {
if (et.getText().toString().length() > 0) {
String src = et.getText().toString();
String origin = currencyFormat(src);
if(!src.equals(origin)) {
et.setText(currencyFormat(et.getText().toString()));
}
}
}
Try below code :
private String current = "";
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if(!s.toString().equals(current)){
[your_edittext].removeTextChangedListener(this);
String cleanString = s.toString().replaceAll("[$,.]", "");
double parsed = Double.parseDouble(cleanString);
String formatted = NumberFormat.getCurrencyInstance().format((parsed/100));
current = formatted;
[your_edittext].setText(formatted);
[your_edittext].setSelection(formatted.length());
[your_edittext].addTextChangedListener(this);
}
}

Set EditText Digits Programatically with Filters

I am trying to set the digits value of an EditText programatically with pattern "9,999" (where 9 it's digit 0-9). So far I have:
final EditText editText = new EditText(v.getContext());
editText.setLayoutParams(params);
editText.setText("");
editText.setKeyListener(DigitsKeyListener.getInstance("0123456789"));
editText.setInputType(InputType.TYPE_CLASS_NUMBER);
editText.setFilters(new InputFilter[] {new InputFilter.LengthFilter(maxLenght)});
editText.addTextChangedListener(new TextWatcher() {
int len=0;
//int count=0;
#Override
public void afterTextChanged(Editable s) {
String str = editText.getText().toString();
if(str.length()==1&& len <str.length()){//len check for backspace
editText.append(",");
}
}
#Override
public void beforeTextChanged(CharSequence c, int arg1, int arg2, int arg3) {
String str = editText.getText().toString();
len = str.length();
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
String str = editText.getText().toString();
}
});
Which is not best, because:
DigitsKeyListener won't accept "," separator.
When I type "1,0" and
then go 2x backspace I can type "11111". I have to go 3x backspace
and then when I type "11111" it will be "1,1111"
Any ideas?
You could try changing afterTextChange() method to this
#Override
public void afterTextChanged(Editable s) {
try {
String str = String.format("%,d", Long.parseLong(s.toString()
.replaceAll(",", "")));
int pos = editText.getSelectionStart();
editText.removeTextChangedListener(this);
editText.setText(str);
editText.setSelection(pos);
editText.addTextChangedListener(this);
} catch (NumberFormatException e) {
e.printStackTrace();
}
}

Categories