Skip to content

Instantly share code, notes, and snippets.

@abubakrr
Created June 3, 2019 07:53
Show Gist options
  • Save abubakrr/2f4ee39f5cd1d4541e071a1886b02317 to your computer and use it in GitHub Desktop.
Save abubakrr/2f4ee39f5cd1d4541e071a1886b02317 to your computer and use it in GitHub Desktop.
package uz.abubakrr.transfer.view;
import android.content.Context;
import android.graphics.Rect;
import android.text.Editable;
import android.text.InputFilter;
import android.text.InputType;
import android.text.Spanned;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.EditText;
import androidx.appcompat.widget.AppCompatEditText;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;
public class CurrencyEditText extends AppCompatEditText {
private static String prefix = "";
private static final int MAX_LENGTH = 20;
private static final int MAX_DECIMAL = 2;
public int pos = -1;
private static DecimalFormatSymbols formatSymbols;
public static DecimalFormatSymbols getFormatSymbols() {
if (formatSymbols == null) {
formatSymbols = new DecimalFormatSymbols(Locale.ENGLISH);
formatSymbols.setDecimalSeparator('.');
formatSymbols.setGroupingSeparator(' ');
}
return formatSymbols;
}
private CurrencyTextWatcher currencyTextWatcher = new CurrencyTextWatcher(this, prefix);
public CurrencyEditText(Context context) {
this(context, null);
}
public CurrencyEditText(Context context, AttributeSet attrs) {
this(context, attrs, androidx.appcompat.R.attr.editTextStyle);
}
public CurrencyEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
this.setHint(prefix);
this.setFilters(new InputFilter[]{filter, new InputFilter.LengthFilter(MAX_LENGTH)});
}
@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
super.onFocusChanged(focused, direction, previouslyFocusedRect);
if (focused) {
this.addTextChangedListener(currencyTextWatcher);
this.setFilters(new InputFilter[]{filter, new InputFilter.LengthFilter(MAX_LENGTH)});
} else {
this.removeTextChangedListener(currencyTextWatcher);
this.setFilters(new InputFilter[]{});
}
handleCaseCurrencyEmpty(focused);
}
/**
* When currency empty <br/>
* + When focus EditText, set the default text = prefix (ex: VND) <br/>
* + When EditText lose focus, set the default text = "", EditText will display hint (ex:VND)
*/
private void handleCaseCurrencyEmpty(boolean focused) {
if (focused) {
if (getText().toString().isEmpty()) {
setText(prefix);
}
} else {
if (getText().toString().equals(prefix)) {
setText("");
}
}
}
public InputFilter filter = new InputFilter() {
@Override
public CharSequence filter(CharSequence charSequence, int start, int end, Spanned dest, int dstart, int dend) {
String temp = getText().toString() + charSequence.toString();
if (temp.contains(".")) {
if (temp.equals(".")) return "0.";
if (dstart <= temp.indexOf(".")) return null;
String tmp = temp.substring(temp.indexOf(".") + 1);
if (tmp.length() > 2) return "";
}
return null;
}
};
private static class CurrencyTextWatcher implements TextWatcher {
private final EditText editText;
private String previousCleanString;
private String prefix;
private int pos = -1;
CurrencyTextWatcher(EditText editText, String prefix) {
this.editText = editText;
this.prefix = prefix;
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
Log.d("BEFORETEXT", "Char " + s +
" start: " + start +
" count: " + count +
" after: " + after);
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (count == 1) pos = start + 1;
else if (before == 1) pos = start;
Log.d("ONTEXTCHANGED", "Char " + s +
" start: " + start +
" before: " + before +
" count: " + count);
}
@Override
public void afterTextChanged(Editable editable) {
String str = editable.toString();
if (str.length() < prefix.length()) {
editText.setText(prefix);
editText.setSelection(prefix.length());
return;
}
if (str.equals(prefix)) {
return;
}
// cleanString this the string which not contain prefix and ,
String cleanString = str.replace(prefix, "").replaceAll("[ ]", "");
// for prevent afterTextChanged recursive call
if (cleanString.equals(previousCleanString) || cleanString.isEmpty()) {
return;
}
previousCleanString = cleanString;
String formattedString;
if (cleanString.contains(".")) {
formattedString = formatDecimal(cleanString);
} else {
formattedString = formatInteger(cleanString);
}
editText.removeTextChangedListener(this); // Remove listener
int old = editable.toString().length();
int newSize = formattedString.length();
Log.d("SIZESMY", "Old: " + old + " new " + newSize);
Log.d("SIZESMY", "Old: " + editable.toString() + " new " + formattedString);
if (old < newSize) {
pos++;
} else if (old > newSize) pos--;
editText.setText(formattedString);
handleSelection();
editText.addTextChangedListener(this); // Add back the listener
}
private String formatInteger(String str) {
BigDecimal parsed = new BigDecimal(str);
DecimalFormat formatter =
new DecimalFormat(prefix + "#,###", getFormatSymbols());
return formatter.format(parsed);
}
private String formatDecimal(String str) {
if (str.equals(".")) {
return prefix + ".";
}
BigDecimal parsed = new BigDecimal(str);
// example pattern VND #,###.00
DecimalFormat formatter = new DecimalFormat(prefix + "#,###." + getDecimalPattern(str),
getFormatSymbols());
formatter.setRoundingMode(RoundingMode.DOWN);
return formatter.format(parsed);
}
/**
* It will return suitable pattern for format decimal
* For example: 10.2 -> return 0 | 10.23 -> return 00, | 10.235 -> return 000
*/
private String getDecimalPattern(String str) {
int decimalCount = str.length() - str.indexOf(".") - 1;
StringBuilder decimalPattern = new StringBuilder();
for (int i = 0; i < decimalCount && i < MAX_DECIMAL; i++) {
decimalPattern.append("0");
}
return decimalPattern.toString();
}
private void handleSelection() {
if (editText.getText().length() <= MAX_LENGTH) {
if (pos != -1)
editText.setSelection(Math.min(pos, editText.getText().length()));
else
editText.setSelection(editText.getText().length());
} else {
editText.setSelection(MAX_LENGTH);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment