如何在编辑格式类似于美国货币的 EditText 字段时重新定位光标 - Android
How to reposition cursor while editing EditText field which is formatted like US currency- Android
我正在按照美国货币格式格式化编辑文本字段,在字段中键入数字时,假设“12345678”看起来像“12,345,678”。
为此,我使用了 TextWatcher
和 afterTextChanged(...)
方法,我将输入的文本格式化为:
@Override
public void afterTextChanged(Editable editable) {
String str = editable.toString();
String number = str.replaceAll("[,]", "");
if (number.equals(previousNumber) || number.isEmpty()) {
return;
}
previousNumber = number;
DecimalFormat formatter = new DecimalFormat("#,###.##", new DecimalFormatSymbols(Locale.US));
String formattedString = formatter.format(number);
editText.setText(formattedString);
}
此外,我正在使用 onSelectionChanged(...)
回调方法,例如:
@Override
protected void onSelectionChanged(int selStart, int selEnd) {
this.setSelection(selStart);
}
但是这里 'selStart' 不是 return 数字的实际长度,因为它不包括每种货币中“,”的数量。
例如:对于“12,345,678”,它 returns 算作 8 而不是 10。
这就是为什么我无法将光标放在字段末尾的原因。
以下是我使用的自定义EditText代码:
public class CurrencyEditText extends AppCompatEditText {
private static final int MAX_LENGTH = 16;
private static final int MAX_DECIMAL_DIGIT = 2;
private static String prefix = "";
private CurrencyTextWatcher currencyTextWatcher = new CurrencyTextWatcher(this, prefix);
public CurrencyEditText(Context context) {
this(context, null);
}
public CurrencyEditText(Context context, AttributeSet attrs) {
this(context, attrs, android.support.v7.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);
}
@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
super.onFocusChanged(focused, direction, previouslyFocusedRect);
if (focused) {
this.addTextChangedListener(currencyTextWatcher);
} else {
this.removeTextChangedListener(currencyTextWatcher);
}
handleCaseCurrencyEmpty(focused);
}
private void handleCaseCurrencyEmpty(boolean focused) {
if (!focused) {
if (getText().toString().equals(prefix)) {
setText("");
}
}
}
private static class CurrencyTextWatcher implements TextWatcher {
private final EditText editText;
DecimalFormat formatter;
private String previousNumber;
private String prefix;
Context mContext;
CurrencyTextWatcher(EditText editText, String prefix) {
this.editText = editText;
this.prefix = prefix;
formatter = new DecimalFormat("#,###.##", new DecimalFormatSymbols(Locale.US));
}
@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 editable) {
String str = editable.toString();
String number = str.replaceAll("[,]", "");
if (number.equals(previousNumber) || number.isEmpty()) {
return;
}
previousNumber = number;
String formattedString = prefix + formatNumber(number);
editText.removeTextChangedListener(this);
editText.setText(formattedString);
//handleSelection();
editText.addTextChangedListener(this);
}
private String formatNumber(String number) {
if (number.contains(".")) {
return formatDecimal(number);
}
return formatInteger(number);
}
private String formatInteger(String str) {
BigDecimal parsed = new BigDecimal(str);
return formatter.format(parsed);
}
private String formatDecimal(String str) {
if (str.equals(".")) {
return "0.";
}
BigDecimal parsed = new BigDecimal(str);
DecimalFormat formatter = new DecimalFormat("#,##0." + getDecimalPattern(str),
new DecimalFormatSymbols(Locale.US));
formatter.setRoundingMode(RoundingMode.DOWN);
return formatter.format(parsed);
}
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_DIGIT; i++) {
decimalPattern.append("0");
}
return decimalPattern.toString();
}
/*private void handleSelection() {
if (editText.getText().length() <= MAX_LENGTH) {
editText.setSelection(editText.getText().length());
}
}*/
}
@Override
protected void onSelectionChanged(int selStart, int selEnd) {
this.setSelection(selStart);
}
}
我不想使用 this.setSelection(lengthOfTheEnteredText)
,因为它会在您编辑字段时产生问题!
onSelectionChanged(...)
不考虑“,”的计数的原因可能是什么?
在对这个问题进行更多探索之后,我找到了解决方案。我在哪里计算光标位置。我已经从我的代码中删除了 onSelectionChanged(...)
方法,我正在处理 afterTextChanged(...)
方法中的选择。在以下代码中,我对 afterTextChanged(...)
进行了更改:
@Override
public void afterTextChanged(Editable editable) {
String str = editable.toString();
String number = str.replaceAll("[,]", "");
if (number.equals(previousNumber) || number.isEmpty()) {
return;
}
previousNumber = number;
int startText, endText;
startText = editText.getText().length();
int selectionStart = editText.getSelectionStart();
String formattedString = prefix + formatNumber(number);
editText.removeTextChangedListener(this);
editText.setText(formattedString);
endText = editText.getText().length();
int selection = (selectionStart + (endText - startText));
editText.setSelection(selection);
editText.addTextChangedListener(this);
}
我正在按照美国货币格式格式化编辑文本字段,在字段中键入数字时,假设“12345678”看起来像“12,345,678”。
为此,我使用了 TextWatcher
和 afterTextChanged(...)
方法,我将输入的文本格式化为:
@Override
public void afterTextChanged(Editable editable) {
String str = editable.toString();
String number = str.replaceAll("[,]", "");
if (number.equals(previousNumber) || number.isEmpty()) {
return;
}
previousNumber = number;
DecimalFormat formatter = new DecimalFormat("#,###.##", new DecimalFormatSymbols(Locale.US));
String formattedString = formatter.format(number);
editText.setText(formattedString);
}
此外,我正在使用 onSelectionChanged(...)
回调方法,例如:
@Override
protected void onSelectionChanged(int selStart, int selEnd) {
this.setSelection(selStart);
}
但是这里 'selStart' 不是 return 数字的实际长度,因为它不包括每种货币中“,”的数量。 例如:对于“12,345,678”,它 returns 算作 8 而不是 10。 这就是为什么我无法将光标放在字段末尾的原因。
以下是我使用的自定义EditText代码:
public class CurrencyEditText extends AppCompatEditText {
private static final int MAX_LENGTH = 16;
private static final int MAX_DECIMAL_DIGIT = 2;
private static String prefix = "";
private CurrencyTextWatcher currencyTextWatcher = new CurrencyTextWatcher(this, prefix);
public CurrencyEditText(Context context) {
this(context, null);
}
public CurrencyEditText(Context context, AttributeSet attrs) {
this(context, attrs, android.support.v7.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);
}
@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
super.onFocusChanged(focused, direction, previouslyFocusedRect);
if (focused) {
this.addTextChangedListener(currencyTextWatcher);
} else {
this.removeTextChangedListener(currencyTextWatcher);
}
handleCaseCurrencyEmpty(focused);
}
private void handleCaseCurrencyEmpty(boolean focused) {
if (!focused) {
if (getText().toString().equals(prefix)) {
setText("");
}
}
}
private static class CurrencyTextWatcher implements TextWatcher {
private final EditText editText;
DecimalFormat formatter;
private String previousNumber;
private String prefix;
Context mContext;
CurrencyTextWatcher(EditText editText, String prefix) {
this.editText = editText;
this.prefix = prefix;
formatter = new DecimalFormat("#,###.##", new DecimalFormatSymbols(Locale.US));
}
@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 editable) {
String str = editable.toString();
String number = str.replaceAll("[,]", "");
if (number.equals(previousNumber) || number.isEmpty()) {
return;
}
previousNumber = number;
String formattedString = prefix + formatNumber(number);
editText.removeTextChangedListener(this);
editText.setText(formattedString);
//handleSelection();
editText.addTextChangedListener(this);
}
private String formatNumber(String number) {
if (number.contains(".")) {
return formatDecimal(number);
}
return formatInteger(number);
}
private String formatInteger(String str) {
BigDecimal parsed = new BigDecimal(str);
return formatter.format(parsed);
}
private String formatDecimal(String str) {
if (str.equals(".")) {
return "0.";
}
BigDecimal parsed = new BigDecimal(str);
DecimalFormat formatter = new DecimalFormat("#,##0." + getDecimalPattern(str),
new DecimalFormatSymbols(Locale.US));
formatter.setRoundingMode(RoundingMode.DOWN);
return formatter.format(parsed);
}
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_DIGIT; i++) {
decimalPattern.append("0");
}
return decimalPattern.toString();
}
/*private void handleSelection() {
if (editText.getText().length() <= MAX_LENGTH) {
editText.setSelection(editText.getText().length());
}
}*/
}
@Override
protected void onSelectionChanged(int selStart, int selEnd) {
this.setSelection(selStart);
}
}
我不想使用 this.setSelection(lengthOfTheEnteredText)
,因为它会在您编辑字段时产生问题!
onSelectionChanged(...)
不考虑“,”的计数的原因可能是什么?
在对这个问题进行更多探索之后,我找到了解决方案。我在哪里计算光标位置。我已经从我的代码中删除了 onSelectionChanged(...)
方法,我正在处理 afterTextChanged(...)
方法中的选择。在以下代码中,我对 afterTextChanged(...)
进行了更改:
@Override
public void afterTextChanged(Editable editable) {
String str = editable.toString();
String number = str.replaceAll("[,]", "");
if (number.equals(previousNumber) || number.isEmpty()) {
return;
}
previousNumber = number;
int startText, endText;
startText = editText.getText().length();
int selectionStart = editText.getSelectionStart();
String formattedString = prefix + formatNumber(number);
editText.removeTextChangedListener(this);
editText.setText(formattedString);
endText = editText.getText().length();
int selection = (selectionStart + (endText - startText));
editText.setSelection(selection);
editText.addTextChangedListener(this);
}