一、起因
一個需求,類似微信將群,即多選好友之后,在頁面有一個列表顯示已選好友的頭像,這是如果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 兩個方法一下。
--- 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;
}
});
三、結果
結果無非就是可以監聽到了唄。