EditText输入内容拦截和监听删除

hackernew
发布于 2021-2-26 10:30
浏览
0收藏

前言


有时候我们会有一些特殊的需求,需要对输入框进行特殊的处理,比如:

  • 对输入内容去除特殊字符操作,或拦截输入内容提交
  • 监听软件盘删除按钮点击事件,并能在一定条件下拦截
  • 监听输入框文字粘贴、复制、全选等


拦截输入内容提交


对于 EditText 的文字监听,我们通常使用的是添加文字变化监听 addTextChangedListener(watcher) ,通过文字变化监听 TextWatcher 对文字作处理,处理后重新设置文字。需要处理死循环的问题(类似递归,要有终止条件)。

其实可以在输入文字提交之前,还未显示到界面时,就对文字进行处理,需要重写方法

    @Override
    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
        return new MyInputConnection(super.onCreateInputConnection(outAttrs), false);
    }

创建自己的输入连接(InputConnection),在 commitText() 方法中返回 false,提交的内容将会被拦截。
具体代码见最后。

 

监听软件盘删除按钮点击事件


对于软键盘删除按键的监听,通常我们使用 setOnKeyListener(l) ,但是在一些非常规特殊情况下不那么好用,比如多行输入时屏蔽换行。

 

监听输入框文字粘贴、复制、全选等


监听输入框文字粘贴、复制、全选等操作,需要重写 onTextContextMenuItem(id) 方法,通过 id 区分操作,重写对应的逻辑。都有哪些操作,也即都有哪些 id 呢?ctrl + 鼠标左键点击 super.onTextContextMenuItem(id) ,查看源码,找到了以下 id:

     *     static final int ID_SELECT_ALL = android.R.id.selectAll;
     *     static final int ID_UNDO = android.R.id.undo;
     *     static final int ID_REDO = android.R.id.redo;
     *     static final int ID_CUT = android.R.id.cut;
     *     static final int ID_COPY = android.R.id.copy;
     *     static final int ID_PASTE = android.R.id.paste;
     *     static final int ID_SHARE = android.R.id.shareText;
     *     static final int ID_PASTE_AS_PLAIN_TEXT = android.R.id.pasteAsPlainText;
     *     static final int ID_REPLACE = android.R.id.replaceText;
     *     static final int ID_ASSIST = android.R.id.textAssist;
     *     static final int ID_AUTOFILL = android.R.id.autofill;

由于源码里并没有开放这些 id 常量,所以只能用 android.R.id.copy 这样的 id。

 

code

/**
 * 扩展输入框。
 * 可拦截:
 *   软件盘删除按钮点击事件;
 *   输入框内容提交;
 *   长按文字菜单选项点击事件(复制、粘贴、全选等)
 */
public class ExtendEditText extends AppCompatEditText {

    public ExtendEditText(Context context) {
        super(context);
    }

    public ExtendEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ExtendEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    /**
     * 监听长按后选项菜单
     * @param id
     *     static final int ID_SELECT_ALL = android.R.id.selectAll;
     *     static final int ID_UNDO = android.R.id.undo;
     *     static final int ID_REDO = android.R.id.redo;
     *     static final int ID_CUT = android.R.id.cut;
     *     static final int ID_COPY = android.R.id.copy;
     *     static final int ID_PASTE = android.R.id.paste;
     *     static final int ID_SHARE = android.R.id.shareText;
     *     static final int ID_PASTE_AS_PLAIN_TEXT = android.R.id.pasteAsPlainText;
     *     static final int ID_REPLACE = android.R.id.replaceText;
     *     static final int ID_ASSIST = android.R.id.textAssist;
     *     static final int ID_AUTOFILL = android.R.id.autofill;
     * @return
     */
    @Override
    public boolean onTextContextMenuItem(int id) {

        boolean handled = false;
        if (mOnTextMenuItemClickListener != null) {
            handled = mOnTextMenuItemClickListener.onTextMenuItemClick(id);
        }

        return handled || super.onTextContextMenuItem(id);
    }

    private OnTextMenuItemClickListener mOnTextMenuItemClickListener;

    /**
     * 设置文字菜单选项点击监听,用于监听粘贴、全选、复制等操作,可以重写这些操作逻辑。
     */
    public void setOnTextMenuItemClickListener(OnTextMenuItemClickListener onTextMenuItemClickListener) {
        mOnTextMenuItemClickListener = onTextMenuItemClickListener;
    }

    /**
     * 文字菜单选项点击监听
     */
    public interface OnTextMenuItemClickListener {
        boolean onTextMenuItemClick(int id);
    }

    /**
     * 输入法
     *
     * @param outAttrs
     * @return
     */
    @Override
    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
        return new MyInputConnection(super.onCreateInputConnection(outAttrs), false);
    }


    private int count;

    class MyInputConnection extends InputConnectionWrapper implements
            InputConnection {

        public MyInputConnection(InputConnection target, boolean mutable) {
            super(target, mutable);
        }


        /**
         * 对输入的内容进行拦截
         *
         * @param text
         * @param newCursorPosition
         * @return
         */
        @Override
        public boolean commitText(CharSequence text, int newCursorPosition) {

            if (mOnCommitTextListener != null) {
                if (!mOnCommitTextListener.onCommitText(text, newCursorPosition)) {
                    return false;
                }
            }

//            // 只能输入汉字
//            if (!text.toString().matches("[\u4e00-\u9fa5]+") && !text.toString().matches("[a-zA-Z]+") && !text.toString().matches("[0-9]")) {
//                ToastUtil.ToastShow(getContext(), "只能输入数字和字母和汉字");
//                return false;
//            }
//
//
//            tips(text.toString());
//
//            if (count > 16) {
//                ToastUtil.ToastShow(getContext(), "最多16个字符");
//                return false;
//            }

            return super.commitText(text, newCursorPosition);
        }

        private void tips(String append) {
            count = 0;

            String text = getText().toString();
            for (int i = 0; i < text.length(); i++) {
                String a = String.valueOf(text.charAt(i));
                if (a.matches("[\u4e00-\u9fa5]+")) {
                    count = count + 2;
                } else {
                    count = count + 1;
                }
            }


            for (int i = 0; i < append.length(); i++) {
                String a = String.valueOf(append.charAt(i));
                if (a.matches("[\u4e00-\u9fa5]+")) {
                    count = count + 2;
                } else {
                    count = count + 1;
                }
            }


        }

        @Override
        public boolean sendKeyEvent(KeyEvent event) {
            if (event.getAction() == KeyEvent.ACTION_DOWN
                    && event.getKeyCode() == KeyEvent.KEYCODE_DEL) {
                if (mOnCommitTextListener != null) {
                    if (mOnCommitTextListener.onDeleteClick()) { // 软键盘删除按钮点击事件拦截。
                        return true;
                    }
                }
            }
            return super.sendKeyEvent(event);
        }

        @Override
        public boolean deleteSurroundingText(int beforeLength, int afterLength) {
            if (beforeLength == 1 && afterLength == 0) {
                return sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN,
                        KeyEvent.KEYCODE_DEL))
                        && sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP,
                        KeyEvent.KEYCODE_DEL));
            }
            return super.deleteSurroundingText(beforeLength, afterLength);
        }
    }


    private OnCommitTextListener mOnCommitTextListener;

    public void setOnCommitTextListener(OnCommitTextListener onCommitTextListener) {
        mOnCommitTextListener = onCommitTextListener;
    }

    public interface OnCommitTextListener {

        /**
         * 输入文字监听回调。可以对输入文字进行拦截,处理后再显示(比如去掉特殊字符)。
         * @param text
         * @param newCursorPosition
         * @return
         */
        boolean onCommitText(CharSequence text, int newCursorPosition);

        /**
         * 当软键盘删除按钮点击时的回调方法。
         * @return true,拦截;false,默认
         */
        boolean onDeleteClick();
    }
}

 

 

分类
已于2021-2-26 10:30:07修改
收藏
回复
举报
回复
    相关推荐