Created
June 3, 2019 07:53
-
-
Save abubakrr/2f4ee39f5cd1d4541e071a1886b02317 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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