一、背景介绍

我的需求是:使用系统软键盘进行内容输入,输入入口的控件是AppCompatEditText,在内容显示到屏幕之前,进行拦截,并根据需求修改输入内容,再显示到屏幕上。

二、思路

自定义EditText继承自AppCompatEditText,利用InputConnectionWrapper拦截内容,再提交显示到屏幕上。

三、实现过程

(1)自定义EditText

public class ExtendEditText  extends AppCompatEditText {
    private boolean isPaste = false;
    public ExtendEditText(@NonNull Context context) {
        super(context);
    }

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

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

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

    class MyInputConnection extends InputConnectionWrapper implements InputConnection {

        /**
         * Initializes a wrapper.
         *
         * <p><b>Caveat:</b> Although the system can accept {@code (InputConnection) null} in some
         * places, you cannot emulate such a behavior by non-null {@link InputConnectionWrapper} that
         * has {@code null} in {@code target}.</p>
         *
         * @param target  the {@link InputConnection} to be proxied.
         * @param mutable set {@code true} to protect this object from being reconfigured to target
         *                another {@link InputConnection}.  Note that this is ignored while the target is {@code null}.
         */
        public MyInputConnection(InputConnection target, boolean mutable) {
            super(target, mutable);
        }

        @Override
        public boolean commitText(CharSequence text, int newCursorPosition) {
            Log.i("shawn", "commitText:" + text + " newCursorPosition:" + newCursorPosition);
            text = "被修改了";
            return super.commitText(text, newCursorPosition);
        }
    }

    /**
     * 监听菜单事件:全选、复制、粘贴
     * @param id
     * @return
     */
    @Override
    public boolean onTextContextMenuItem(int id) {
        if (id == android.R.id.copy) {
            Log.i("shawn", "onTextContextMenuItem 复制");
        } else if (id == android.R.id.paste) {
            isPaste = true;
            Log.i("shawn", "onTextContextMenuItem 粘贴");
        } else if (id == android.R.id.selectAll) {
            Log.i("shawn", "onTextContextMenuItem 全选");
        } else {
            Log.i("shawn", "onTextContextMenuItem id" + id);
        }
        return super.onTextContextMenuItem(id);
    }

    public boolean isPaste() {
        return isPaste;
    }
}

commitText修改实现自己的需求。

PS:onTextContextMenuItem是对菜单选项的监听

(2)利用TextWatcher实现一些替换文本的需求

editText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                Log.i(TAG, "beforeTextChanged 内容:" + s + "   粘贴输入:"+editText.isPaste() + "  start:"+start+ "  count:"+count+ "  after:"+after);
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                Log.i(TAG, "onTextChanged 内容:" + s + "   粘贴输入:"+editText.isPaste()+ "  start:"+start+ "  count:"+count);
if (editorET.isPaste()) {
                    // 1.获取粘贴内容
                    // 2.修改粘贴内容
                    // 3.替换粘贴内容
                    if (!StringUtils.isEmpty(changeStr)) {
                        Editable editable = editorET.getText();
                        if (editable != null) {
                            editable.replace(start, replaceEnd, changeStr);
                        }
                    }
                }
            }

            @Override
            public void afterTextChanged(Editable s) {
                Log.i(TAG, "afterTextChanged 内容:" + s + "   粘贴输入:"+editText.isPaste());
            }
        });

四:注意事项

EditText的commitText和onTextChanged方法调用次数为什么不一致?

在Android中,EditText是一个用于接收和显示文本内容的控件。commitTextonTextChangedEditText的两个不同的方法,用于处理文本变化的情况,但它们的调用次数可能会因为不同的操作和事件触发而不一致。

  1.  commitText方法: commitText方法是InputConnection接口中的一个方法,用于将指定的文本插入到EditText中。通常情况下,这个方法是由输入法(软键盘)来调用的,当用户在键盘上点击一个字符时,输入法会调用commitText来将该字符插入到EditText中。因此,commitText的调用次数取决于用户的输入操作和输入法的行为。不同的输入法可能会以不同的方式调用commitText,所以调用次数可能会有所不同。

  2. onTextChanged方法: onTextChanged方法是TextWatcher接口中的一个方法,用于在EditText中的文本内容发生变化时被调用。它会在文本发生变化时(插入、删除、替换等)被触发。这意味着无论是通过用户的输入、代码中的修改,还是通过其他方式改变文本内容,都有可能触发onTextChanged方法的调用。

因此,commitText方法的调用次数取决于用户的输入操作和输入法的行为,而onTextChanged方法的调用次数取决于文本内容的变化。由于两者的触发条件不同,所以它们的调用次数可能会出现不一致的情况。

如果您在特定情况下发现commitTextonTextChanged的调用次数不一致,可以考虑检查您的代码逻辑、输入法的行为以及对EditText的操作,以找出导致这种不一致性的原因

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐