android - фильтр длины EditText не работает должным образом

Во-первых, я должен сказать, что читал подобные вопросы и ответы здесь, на SO, и этот вопрос в основном является дубликатом этот вопрос и многие другие, но ответы на эти вопросы не работают так, как я хочу.

Проблема:

Настройка фильтра длины в моем EditText программно выглядит следующим образом:

editText.setFilters(new InputFilter[]{new LengthFilter(10)} );

Единственное, что он делает, это скрывает текст, превышающий лимит в EditText. Он по-прежнему показывает длинный (неограниченный) текст в окне предложений, и мне приходится удалять (возврат) для каждой буквы, которая проходит, прежде чем я смогу удалить то, что показано в EditText.

Предлагаемые решения:

  1. Установка InputType на textFilter.

    Программно я сделал это:

    editText.setInputType( InputType.TYPE_TEXT_VARIATION_FILTER );
    

    Он скрывает предложения, но неограниченный текст все еще присутствует, и мне все еще приходится использовать клавишу Backspace, чтобы удалить буквы, которых не должно быть.

  2. Установка InputType на textNoSuggestions|textVisiblePassword.

    Программно я сделал это (пришлось добавить TYPE_CLASS_TEXT, иначе это не сработало бы):

    editText.setInputType( InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD );
    

    Этот работает, но проблема в том, что он останавливает «жестовый ввод» и меняет шрифт на моноширинный.

Лучшие решения?
Как видите, эти два метода на самом деле работают не без дополнительных проблем. Есть ли другой способ сделать это, который я пропустил. Должен ли я просто использовать TextWatcher, если я хочу продолжать печатать жестами и предложения?


person ROAR    schedule 19.02.2018    source источник


Ответы (1)


Вместо этого я использовал TextWatcher. Я не уверен, что это лучший способ сделать это, но он работает с предложениями и не отключает набор жестов или меняет стиль шрифта. Вот как я это сделал (я новичок в Android, поэтому, если это нуждается в улучшении, не стесняйтесь, дайте мне знать).

Я добавил пример в комментарии, чтобы прояснить, что происходит.

Сделайте эти глобальные переменные:

private boolean mWatcherIsBlocked = false;
private String mBeforeChange;
private String mFilteredString; 
private int mCursorPosition = 0;

Затем создайте TextWatcher и добавьте его в свой EditText.

final int maxLength = 10; // desired length limit

/** 
 * lets say our EditText is showing "abcdefgh". We select "cdef" from it and 
 * paste a new text "ijklmnop" in the middle. What we should get according to
 * our maxLength is this: 
 * (1) "ab" (0th up to the letter from before_change_text we were selecting) + 
 * (2) "ijklmn" (part of the text we pasted minus the number of letters the whole 
 *      after_change_text goes over the 10 letter limit) + 
 * (3) "gh" (last part of before_change_text that wasn't selected)
 * 
 * so the new text has to be "abijkmngh"
 */

TextWatcher textWatcher = new TextWatcher() {
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        // get before_change_text if textWatcher isn't blocked
        if (!mWatcherIsBlocked) mBeforeChange = s.toString();
    }
    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        if (!mWatcherIsBlocked){
            // get after_change_text if textWatcher isn't blocked
            String after = s.toString();
            // if after_change_text's length is bigger than the limit 
            if (after.length() > maxLength) {
                // see how much it goes over the limit
                int over = after.length() - maxLength;
                // add parts (1) and (2) like our example above
                String st = mBeforeChange.substring(0, start) + // (1)
                            after.substring(start, start + count - over); // (2)
                // get where the cursor position should be after pasting (
                // = after the last letter we could paste = length of (1) + (2) )
                mCursorPosition = st.length();
                // now add part (3) of our text to the first two
                st += mBeforeChange.substring(
                          mBeforeChange.length() - (maxLength - st.length()), 
                          mBeforeChange.length());
                // now assign this new text to a global variable
                mFilteredString = st;
            } else { 
                // if after_change_text hasn't gone over the limit assign it 
                // directly to our global variable
                mFilteredString = s.toString();
            }
        }
    }
    @Override
    public void afterTextChanged(Editable s) {
        // if filtered text is not the same as unfiltered text 
        // or textWatcher is not blocked
        if (!mFilteredString.equals(s.toString()) && !mWatcherIsBlocked) {
            // block textWatcher to avoid infinite loops created by setText 
            // (this might not work as I well as I think!)
            mWatcherIsBlocked = true;
            // set new text to our EditText
            editText.setText(mFilteredString);
            // set its cursor position 
            editText.setSelection(mCursorPosition);
            // unblock the textWatcher
            mWatcherIsBlocked = false;
        }
    }
};

// add the TextWatcher to our EditText
editText.addTextChangedListener(textWatcher);
person ROAR    schedule 20.02.2018