Переопределить getText EditText - PullRequest
       38

Переопределить getText EditText

3 голосов
/ 03 апреля 2019

Я хочу переопределить getText() EditText.

Я получаю такую ​​строку: "12,345,678"

Моя цель - просто удалить запятые и вернуть Editable, но когда смой код я получаю сообщение об ошибке.

public class AmountEditText extends EditText {
    @Override
    public Editable getText() {
        Editable s = super.getText();
        if(s!=null && s.length()>0) {
            if (s.toString().contains(",")) {
                return new SpannableStringBuilder(s.toString().replace(",", ""));
            }
        }
        return s;
    }
    private TextWatcher watcher = new TextWatcher() {



        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            int position = getSelectionStart();
            int nbCommaBefore;
            int nbCommaAfter;
            String str = s.toString();
            String finalStr;
            String formattedStr;
            nbCommaBefore  = str.length() - str.replace(",", "").length();
            boolean containsDot = false;
            if (str.contains(".")) {
                containsDot = true;
                formattedStr = str.split("\\.")[0];

            } else {
                formattedStr = str;
            }
            if (!s.toString().isEmpty()) {
                removeTextChangedListener(watcher);
                formattedStr = formattedStr.replace(",", "");
                formattedStr = formattedStr.replaceAll("(\\d)(?=(\\d{3})+$)", "$1,");
                if (containsDot) {
                    if (str.split("\\.").length != 1) {
                        finalStr = formattedStr + "." + str.split("\\.")[1].replace(",", "");
                    } else {
                        finalStr = formattedStr + ".";
                    }
                } else {
                    finalStr = formattedStr;
                }
                nbCommaAfter  = finalStr.length() - finalStr.replace(",", "").length();
                setText(finalStr);
                if (position == str.length()){
                    setSelection(finalStr.length());
                }
                else if (position == 0)
                {
                    setSelection(0);
                }
                else if (nbCommaBefore < nbCommaAfter){
                    setSelection(position + 1);
                }

                else if (nbCommaAfter < nbCommaBefore){
                    setSelection(position - 1);
                }
                else{
                    setSelection(position);
                }
                addTextChangedListener(watcher);
            }
        }

        @Override
        public void afterTextChanged(Editable s) {
        }

    };

    public AmountEditText(Context context) {
        this(context, null);
    }

    public AmountEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        addTextChangedListener(watcher);
    }

    public AmountEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        addTextChangedListener(watcher);
    }
}

E / MessageQueue-JNI: исключение в обратном вызове MessageQueue: handleReceiveCallback E / MessageQueue-JNI: java.lang.IndexOutOfBoundsException: setSpan (0 ... 5) заканчивается за длину 4 в android.text.SpannableStringBuilder.checkRange (SpannableStringBuilder.java:1265) в android.text.SpannableStringBuilder.setSpan (SpannableStringBuilder.java:684) в android.text.Silnring.Suна android.widget.SpellChecker $ SpellParser.setRangeSpan (SpellChecker.java:532) на android.widget.SpellChecker $ SpellParser.parse (SpellChecker.java:515) на android.widget.SpellChecker.sjll2Check (SpellCheck (atllCheck)android.widget.Editor.updateSpellCheckSpans (Editor.java:679) в android.widget.Editor.sendOnTextChanged (Editor.java:1249) в иroid.widget.TextView.sendOnTextChanged (TextView.java:8191) в android.widget.TextView.setText (TextView.java:4483) в android.widget.TextView.setText (TextView.java:4337) в android.w.txt.setText (EditText.java:89) в android.widget.TextView.setText (TextView.java:4312) в org.newtonproject.newpay.widgetlib.AmountEditText $ 1.onTextChanged (AmountEditText.java): 101

Я хотел бы уточнить, что ошибка не исходит от моего onTextChanged, потому что все работает хорошо без getText() override

РЕДАКТИРОВАТЬ : пользователь может ввести число, я добавлюнесколько запятых для того, чтобы отформатировать число.Но когда я переопределяю getText(), я хочу удалить эти запятые таким образом, мне не нужно фильтровать возврат getText() каждый раз

Ответы [ 4 ]

2 голосов
/ 03 апреля 2019

Хорошо, я отладил это и обнаружил, что проблема была в этой строке

if (position == str.length()){
    setSelection(finalStr.length());
}

lenght() выходит за границы для выбора набора, так как он основан на 0

просто измените свой код, и он будет работать правильно

if (position == str.length()){
   setSelection(finalStr.length() - 1);
}

При необходимости, полный код здесь (я использовал AppCompatEditText, но это то же самое):

public class AmountEditText extends android.support.v7.widget.AppCompatEditText {
    @Override
    public Editable getText() {
        Editable s = super.getText();
        if(s!=null && s.length()>0) {
            if (s.toString().contains(",")) {
                return new SpannableStringBuilder(s.toString().replace(",", ""));
            }
        }
        return s;
    }
    private TextWatcher watcher = new TextWatcher() {



        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            int position = getSelectionStart();
            int nbCommaBefore;
            int nbCommaAfter;
            String str = s.toString();
            String finalStr;
            String formattedStr;
            nbCommaBefore  = str.length() - str.replace(",", "").length();
            boolean containsDot = false;
            if (str.contains(".")) {
                containsDot = true;
                formattedStr = str.split("\\.")[0];

            } else {
                formattedStr = str;
            }
            if (!s.toString().isEmpty()) {
                removeTextChangedListener(watcher);
                formattedStr = formattedStr.replace(",", "");
                formattedStr = formattedStr.replaceAll("(\\d)(?=(\\d{3})+$)", "$1,");
                if (containsDot) {
                    if (str.split("\\.").length != 1) {
                        finalStr = formattedStr + "." + str.split("\\.")[1].replace(",", "");
                    } else {
                        finalStr = formattedStr + ".";
                    }
                } else {
                    finalStr = formattedStr;
                }
                nbCommaAfter  = finalStr.length() - finalStr.replace(",", "").length();
                setText(finalStr);
                if (position == str.length()){
                    setSelection(finalStr.length() - 1);
                }
                else if (position == 0)
                {
                    setSelection(0);
                }
                else if (nbCommaBefore < nbCommaAfter){
                    setSelection(position + 1);
                }

                else if (nbCommaAfter < nbCommaBefore){
                    setSelection(position - 1);
                }
                else{
                    setSelection(position);
                }
                addTextChangedListener(watcher);
            }
        }

        @Override
        public void afterTextChanged(Editable s) {
        }

    };

    public AmountEditText(Context context) {
        this(context, null);
    }

    public AmountEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        addTextChangedListener(watcher);
    }

    public AmountEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        addTextChangedListener(watcher);
    }
}

Дайте мне знать, помогло ли это!

1 голос
/ 03 апреля 2019

В вашем случае вы не можете переопределить getText() и изменить размер, используя TextWatcher одновременно.

Проверьте исходный код Android ниже и вы поймете, почему

SpannableStringBuilder.java

public void setSpan(Object what, int start, int end, int flags) {
    setSpan(true, what, start, end, flags, true/*enforceParagraph*/);
}

private void setSpan(boolean send, Object what, int start, int end, int flags,
            boolean enforceParagraph) {
    checkRange("setSpan", start, end);
}

private void checkRange(final String operation, int start, int end) {
    ...
    int len = length();
    if (start > len || end > len) {
        throw new IndexOutOfBoundsException(operation + " " +
                    region(start, end) + " ends beyond length " + len); // here is you exception
    }
}

public int length() {
    return mText.length - mGapLength;
}

SpellChecker.java

private void setRangeSpan(Editable editable, int start, int end) {
    ...
    editable.setSpan(mRange, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}

public void parse(int start, int end) {
    ...
    if (parseEnd > start) {
        setRangeSpan((Editable) mTextView.getText(), start, parseEnd); // I think the error happened from here, they use your getText() function here and receive shorter string, but the start, parseEnd still stick with original string
        parse();
    }
}

Решение .
Вы можете просто определить новую функцию, такую ​​как getBeautifulText().

0 голосов
/ 03 апреля 2019

На основании требований в вашем вопросе:

Пользователь может ввести номер, я добавлю несколько запятых, чтобы отформатировать номер. Но когда я переопределяю getText (), я хочу удалить эти запятые

Полагаю, вы могли бы использовать гораздо более простое решение, включающее DecimalFormat:

class Formatter {
    private final DecimalFormat f = new DecimalFormat(",###");
    private final DecimalFormat o = new DecimalFormat("#");

    String withCommas(String in) {
        try {
            return withCommas(Long.parseLong(in));
        } catch (NumberFormatException e) {
            e.printStackTrace();
            return withCommas(Long.MIN_VALUE);
        }
    }

    String withCommas(long in) {
        return f.format(in);
    }

    Number stripCommas(String in) {
        try {
            return f.parse(in);
        } catch (ParseException e) {
            return Long.MIN_VALUE;
        }
    }

    String stripCommasAsString(String in) {
        return o.format(stripCommas(in));
    }
}

Что дает:

final long num = 12345678L;
final Formatter f = new Formatter();

assertEquals("12,345,678", f.withCommas("12345678"));
assertEquals("12,345,678", f.withCommas(num));
assertEquals(num, f.stripCommas("12,345,678");
assertEquals("12345678", f.stripCommasAsString("12,345,678"));
0 голосов
/ 03 апреля 2019

Попробуйте, это поможет вам

editText.addTextChangedListener(new TextWatcher() {
            boolean isEdiging;

            public void onTextChanged(CharSequence s, int start, int before, int count) {
            }

            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }

            public void afterTextChanged(Editable s) {
                if (isEdiging) return;
                isEdiging = true;
                String str = s.toString().replaceAll("[^\\d]", "");
                double s1 = 0;
                try {
                    s1 = Double.parseDouble(str);
                } catch (NumberFormatException e) {
                    e.printStackTrace();
                }
                NumberFormat nf2 = NumberFormat.getInstance(Locale.ENGLISH);
                ((DecimalFormat) nf2).applyPattern("###,###.###");
                s.replace(0, s.length(), nf2.format(s1));

                if (s.toString().equals("0")) {
                    editText.setText("");
                }
                isEdiging = false;
            }
        });
...