从华为P9软键盘删除时无响应到InputConnectionWrapper

一、起因

一个需求,类似微信将群,即多选好友之后,在页面有一个列表显示已选好友的头像,这是如果Edittext内容为空并且按下软键盘的删除键,第一次让头像变灰,第二次则删减最后一个已经勾选的成员。

效果大概如下图:

联动.gif

实现就实现呗,按道理我们搞一个Edittext,然后按照如下代码,应该是没什么问题的

        mEt.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                if (keyCode == KeyEvent.KEYCODE_DEL && event.getAction() == KeyEvent.ACTION_DOWN) {
                    String content = mEt.getText().toString();
                    if (TextUtils.isEmpty(content)) {
                        mTvResult.setText("原生Et 无内容");
                    }else{
                        mTvResult.setText("原生Et DEL_DOWN:  "+content);
                    }
                }
                return false;
            }
        });

但是,部分机型,比如华为P9,当Edittext内容为空时,他就根本无法响应软键盘的删除监听,搞事情!

二、经过 (解决办法)

先看一些解决问题后的代码:

MainActivity

public class MainActivity extends AppCompatActivity {

    private EditText mEt;
    private ZanyEditText mZanyEt;
    private TextView mTvResult;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mEt = (EditText) findViewById(R.id.mEt);
        mZanyEt = (ZanyEditText) findViewById(R.id.mZanyEt);
        mTvResult = (TextView) findViewById(R.id.mTvResult);


        mEt.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                if (keyCode == KeyEvent.KEYCODE_DEL && event.getAction() == KeyEvent.ACTION_DOWN) {
                    String content = mEt.getText().toString();
                    if (TextUtils.isEmpty(content)) {
                        mTvResult.setText("原生Et 无内容");
                    }else{
                        mTvResult.setText("原生Et DEL_DOWN:  "+content);
                    }
                }
                return false;
            }
        });

        mZanyEt.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                if (keyCode == KeyEvent.KEYCODE_DEL && event.getAction() == KeyEvent.ACTION_DOWN) {
                    String content = mZanyEt.getText().toString();
                    if (TextUtils.isEmpty(content)) {
                        mTvResult.setText("ZanyEt 无内容");
                    }else{
                        mTvResult.setText("ZanyEt DEL_DEL_DOWN:  "+content);
                    }
                }
                return false;
            }
        });

    }
}

.
.
布局代码





    

    

    


.
.
.
核心文件
ZanyEditText

public class ZanyEditText extends EditText {
    private OnDelKeyEventListener delKeyEventListener;
    public ZanyEditText(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }
    public ZanyEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public ZanyEditText(Context context) {
        super(context);
    }
    @Override
    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
        return new ZanyInputConnection(super.onCreateInputConnection(outAttrs),
                true);
    }
    private class ZanyInputConnection extends InputConnectionWrapper {
        public ZanyInputConnection(InputConnection target, boolean mutable) {
            super(target, mutable);
        }
        @Override
        public boolean sendKeyEvent(KeyEvent event) {
            if (event.getAction() == KeyEvent.ACTION_DOWN
                    && event.getKeyCode() == KeyEvent.KEYCODE_DEL) {
                if (delKeyEventListener != null) {
                    delKeyEventListener.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);
        }
    }
    /**
     * EditText 删除回调
     */
    public void setDelKeyEventListener(OnDelKeyEventListener delKeyEventListener) {
        this.delKeyEventListener = delKeyEventListener;
    }
    public interface OnDelKeyEventListener {
        void onDeleteClick();
    }
}

具体原因不是为什么P9等部分机器身上无法响应删除监听,接下来我们来看看下面这几点:

1、Edittext继承自TextView

2、翻看TextView的代码,里面有一个叫做InputConnection的东西,看起是什么输入连接的意思。

3、InputConnectionWrapper 是 InputConnection的实现类,我们继承这个包装类并且实现 sendKeyEvent 和 deleteSurroundingText 两个方法一下。

InputConnectionWrapper文档

--- sendKeyEvent

Send a key event to the process that is currently attached through this input connection.

将关键事件发送到当前通过此连接的进程。

其实我觉得大概是说怎么处理当前这个软件键的事件

--- deleteSurroundingText

Delete beforeLength characters of text before the current cursor position, and delete afterLength characters of text after the current cursor position, excluding the selection.

.
.
.
回顾核心代码

private class ZanyInputConnection extends InputConnectionWrapper {
        public ZanyInputConnection(InputConnection target, boolean mutable) {
            super(target, mutable);
        }
        @Override
        public boolean sendKeyEvent(KeyEvent event) {
            if (event.getAction() == KeyEvent.ACTION_DOWN
                    && event.getKeyCode() == KeyEvent.KEYCODE_DEL) {
                if (delKeyEventListener != null) {
                    delKeyEventListener.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);
        }
    }

Activity的处理下面的代码就可以顺利监听到删除键了。

  mZanyEt.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                if (keyCode == KeyEvent.KEYCODE_DEL && event.getAction() == KeyEvent.ACTION_DOWN) {
                    String content = mZanyEt.getText().toString();
                    if (TextUtils.isEmpty(content)) {
                        mTvResult.setText("ZanyEt 无内容");
                    }else{
                        mTvResult.setText("ZanyEt DEL_DEL_DOWN:  "+content);
                    }
                }
                return false;
            }
        });

上文ZanyEditText出处

三、结果

结果无非就是可以监听到了呗。

你可能感兴趣的:(从华为P9软键盘删除时无响应到InputConnectionWrapper)