從華為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;
            }
        });

    }
}

.
.
布局代碼

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    android:id="@+id/activity_main"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.amqr.editdemo.MainActivity">


    <EditText
        android:id="@+id/mEt"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:text="原生"

        />

    <com.amqr.editdemo.ZanyEditText
        android:id="@+id/mZanyEt"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="重寫"
        />

    <TextView
        android:id="@+id/mTvResult"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:text="RESULT"
        />

</LinearLayout>

.
.
.
核心文件
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出處

三、結果

結果無非就是可以監聽到了唄。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • ¥開啟¥ 【iAPP實現進入界面執行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個線程,因...
    小菜c閱讀 6,550評論 0 17
  • afinalAfinal是一個android的ioc,orm框架 https://github.com/yangf...
    passiontim閱讀 15,569評論 2 45
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,523評論 25 708
  • 這世上有千萬種等待,最好的那一種,叫做來日可期。 這句話最初是老同學給我留言,后來在微博發現,再后來在心境變化中感...
    zxmmmmmmmm閱讀 1,806評論 1 4
  • 兒時的記憶總會留些抹不去的場景,哪怕當下忙碌的活著忘記了……也會在哪一天,因為,某件事,某句話,某個場景,那些藏在...
    一滴眼淚換一滴水閱讀 368評論 0 0