How to reposition cursor while editing EditText field which is formatted like US currency- Android

浪尽此生 提交于 2019-12-06 11:18:37

问题


I am formatting edit text field as per US currency format, where while typing number in a field, let's say "12345678" it appears like "12,345,678". For this I have used TextWatcher and on afterTextChanged(...) method I am formatting the entered text like:

@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);
    }

Also, I am using onSelectionChanged(...) callback method like:

 @Override
protected void onSelectionChanged(int selStart, int selEnd) {
    this.setSelection(selStart);
}

But here this 'selStart' doesn't return the actual length of number as it excludes the number of "," in every currency. For example: for "12,345,678" it returns count as 8 instead of 10. That's why I am not able to place my cursor at the end of the field.

Following is the code of custom EditText, which I am using:

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);
}

}

I don't want to use this.setSelection(lengthOfTheEnteredText) because it created issue when you edit the field! What could be the reason that onSelectionChanged(...) does not consider the count of "," present in number?


回答1:


After exploring more on this issue, I have found the solution. Where I am calculating the cursor position. I have removed onSelectionChanged(...) method from my code and I am handling selection inafterTextChanged(...) method. In the following code I have made changes in 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);
    }


来源:https://stackoverflow.com/questions/53495433/how-to-reposition-cursor-while-editing-edittext-field-which-is-formatted-like-us

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!