欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2022-03-18 11:08:42
public class ExtendEditText extends AppCompatEditText { public ExtendEditText(Context context) { super(context); } public ExtendEditText(Context context, AttributeSet attrs) { super(context, attrs); } public ExtendEdi...

系列文章目录

前言

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

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

拦截输入内容提交

对于 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();
    }
}

本文地址:https://blog.csdn.net/wangxiaocheng16/article/details/108004851