android-EditText长度过滤器无法正常工作

android-EditText长度过滤器无法正常工作,android,android-edittext,android-inputtype,android-input-filter,Android,Android Edittext,Android Inputtype,Android Input Filter,首先,我必须说,我在这里读过类似的问题和答案,所以这个问题基本上是和其他许多问题的重复,但是这些问题的答案并不是我想要的那样 问题: 以编程方式在我的EditText上设置长度筛选器,如下所示: editText.setFilters(new InputFilter[]{new LengthFilter(10)} ); 它所做的唯一一件事就是在EditText中隐藏超出限制的文本。它仍然在建议框中显示长(无限)文本,我必须删除(退格)每个字母,然后才能删除编辑文本中显示的内容 建议的解决方案:

首先,我必须说,我在这里读过类似的问题和答案,所以这个问题基本上是和其他许多问题的重复,但是这些问题的答案并不是我想要的那样

问题

以编程方式在我的EditText上设置长度筛选器,如下所示:

editText.setFilters(new InputFilter[]{new LengthFilter(10)} );
它所做的唯一一件事就是在EditText中隐藏超出限制的文本。它仍然在建议框中显示长(无限)文本,我必须删除(退格)每个字母,然后才能删除编辑文本中显示的内容

建议的解决方案:

  • 将InputType设置为
    textFilter


    通过编程,我做到了这一点:

    editText.setInputType( InputType.TYPE_TEXT_VARIATION_FILTER );
    
    它隐藏了建议,但无限文本仍然存在,我仍然必须使用退格删除不应该存在的字母

  • 将InputType设置为
    textNoSuggestions | textVisiblePassword


    我通过编程实现了这一点(必须添加
    TYPE\u CLASS\u TEXT
    ,否则它将无法工作):

    这一个确实有效,但问题是它停止了“手势输入”,并将字体更改为单空格

  • 更好的解决方案?

    如您所见,如果没有其他问题,这两种方法实际上无法工作。有没有其他我错过的方法。如果我想保持手势输入和建议,我应该只使用
    文本观察程序吗?

    我最终使用了文本观察程序。我不确定这是否是最好的方法,但它确实可以提供建议,并且不会关闭手势输入或更改字体样式。下面是我是如何做到的(我对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);
    
    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);