简书链接:关于按键回车改变焦点为其他编辑框引发bug解决探索
文章字数:877,阅读全文大约需要3分钟

1
2
3
4
5
6
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (BaseUtil.isEnterKey(actionId, event)) {
onMaterialEnter(v.getText().toString());
}
return true;
}

在按键回车同样触发onEditorAction 返回true 然后发现其他编辑框为空,让他调用其他编辑框焦点,结果会立马调回来,哪怕post()但是软键盘没有此问题。。

因此此种情况怕是要多延长几秒了。目前没想到解决办法。
2022-11-21 14:54:07
终于找到了解决办法,并且代码进行了进一步的封装,还可以防止快速点击,当按键回车返回了true,那么在onEditorActionListenre将不会触发,
另外如果onKey返回false,那么 onEditorAction分别会受到,按下,和抬起的按键事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
/**
* Return true if you have consumed the action, else false.
*
* @param actionId
* @param event
* @return
*/
public static boolean isKeyEnter(int actionId, KeyEvent event) {
boolean result = actionId == EditorInfo.IME_ACTION_DONE ||
actionId == EditorInfo.IME_ACTION_NEXT ||
actionId == EditorInfo.IME_ACTION_GO ||
actionId == EditorInfo.IME_ACTION_SEARCH ||
actionId == EditorInfo.IME_ACTION_SEND ||
(event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER
&& event.getAction() == KeyEvent.ACTION_UP);

return result;
}



/**
* 1 回车抬起触发 0 回车按下触发, 其他 代表返回false,交给系统处理
*
* @param keyCode
* @param event
* @return
*/
public static int isHardKeyEnter(int keyCode, KeyEvent event) {
boolean result =
(event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER
&& event.getAction() == KeyEvent.ACTION_UP);
if (result) {
return 1;

} else if (event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER
&& event.getAction() == KeyEvent.ACTION_DOWN) {
return 0;//自己处理消费
}
return -1;
}
public static void setOnEditorActionEnterAndScanListener(Activity activity, EditText editText, DialogUtils.INotify<EditText> iNotify) {
editText.setOnKeyListener((v, keyCode, event) -> {
int result = BaseUtil.isHardKeyEnter(keyCode, event);
if (result == 1) {//按键回车抬起
AppUtils.closeKeyboard(activity);
iNotify.onNotify(editText);
return true;
} else if (result == 0) {//按键回车按下
return true;

}
return false;
});

editText.setOnEditorActionListener((v, actionId, event) -> {
if (BaseUtil.isKeyEnter(actionId, event)) {
if (ButtonUtils.isFastDoubleClick(actionId)) {
return true;
}
AppUtils.closeKeyboard(activity);
iNotify.onNotify(editText);
}
return true;
});
}

但是又发现了一个问题,
假设第一个编辑框没重写设置,而第二个编辑框设置了,从第一个编辑框按键回车会自动触发第二个编辑框的onKeyEvent从而发起了逻辑,依然是有问题的,要从源头上禁止按键回车改变光标 才能彻底解决问题,
虽然无法调试源码但是根据自定义view重写获取焦点追踪到了调用的代码处,为textview的onKeyUp事件所触发。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
    if ((event.getFlags() & KeyEvent.FLAG_EDITOR_ACTION) != 0
|| shouldAdvanceFocusOnEnter()) {

if (!hasOnClickListeners()) {
View v = focusSearch(FOCUS_DOWN);
if (v != null) {
if (!v.requestFocus(FOCUS_DOWN)) {
throw new IllegalStateException("focus search returned a view "
+ "that wasn't able to take focus!");
}

super.onKeyUp(keyCode, event);
return true;
} else if ((event.getFlags()
& KeyEvent.FLAG_EDITOR_ACTION) != 0) {

InputMethodManager imm = getInputMethodManager();
if (imm != null && imm.isActive(this)) {
imm.hideSoftInputFromWindow(getWindowToken(), 0);
}
}
}




}

另外也要满足inputtype =TYPE_CLASS_TEXT之类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private boolean shouldAdvanceFocusOnEnter() {
if (getKeyListener() == null) {
return false;
}

if (mSingleLine) {
return true;
}

if (mEditor != null
&& (mEditor.mInputType & EditorInfo.TYPE_MASK_CLASS)
== EditorInfo.TYPE_CLASS_TEXT) {
int variation = mEditor.mInputType & EditorInfo.TYPE_MASK_VARIATION;
if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
|| variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_SUBJECT) {
return true;
}
}

return false;
}

2022-11-26 12:28:00
经过源码分析在onEdiAction里面 无论是down还是up全部返回true,这样就不会交给系统处理焦点了,
而响应逻辑就处理按下就好了。
第二个编辑框设置setOnEditActionListenlier然后立马写了尝试发起调用第一个编辑框的获取焦点,结果是 又跳回来了,
如果第一个编辑框没设置焦点相关事件,第二个 触发 第一个, 第一个又调用了 第二个的焦点,也就是第一个的onKeyUp触发,然后执行如下代码

1
2
3
4
5
6
if (!hasOnClickListeners()) {
View v = focusSearch(FOCUS_DOWN);

if (v != null) {
if (!v.requestFocus(FOCUS_DOWN)) {

又让第二个获取了焦点。
去掉input=text 或者非单行,则正常运行,因此目前处理起来有点棘手。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if (mSingleLine) {
return true;
}

if (mEditor != null
&& (mEditor.mInputType & EditorInfo.TYPE_MASK_CLASS)
== EditorInfo.TYPE_CLASS_TEXT) {
int variation = mEditor.mInputType & EditorInfo.TYPE_MASK_VARIATION;
if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
|| variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_SUBJECT) {
return true;
}
}

满足此条件

1
2
3
4
5
6
7
8
9
10
if (mEditor != null && mEditor.mInputContentType != null
&& mEditor.mInputContentType.onEditorActionListener != null
&& mEditor.mInputContentType.enterDown) {
mEditor.mInputContentType.enterDown = false;
if (mEditor.mInputContentType.onEditorActionListener.onEditorAction(
this, EditorInfo.IME_NULL, event)) {
return true;
}
}

目前第一个编辑框
&& mEditor.mInputContentType != 是空的。所以走了shouldAdvanceFocusOnEnter

最后总结,方法是有了,但是要改的地方太多不太现实。。
比如

1
2
3
4
5
public boolean onKeyUp(int keyCode, KeyEvent event) {
if(keyCode==KeyEvent.KEYCODE_ENTER){
return true;
}

这导致硬件回车无法触发光标下移事件

最后的调整版本 就是按键回车这种不应该立马回调,让事件流失掉,就不会连环触发另外一个的按键抬起事件了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
  public static void setOnEditorActionEnterAndScanListener(Activity activity, EditText editText, DialogUtils.INotify<EditText> iNotify) {

editText.setOnKeyListener((v, keyCode, event) -> {
int result = BaseUtil.isHardKeyEnter(keyCode, event);
if (result == 1) {//按键回车抬起
if (BuildConfig.DEBUG) {
Log.w("Event", "down" + event.getDownTime() + event.getEventTime() + "," + event.getEventTime() + ",fucus:" + editText.hasFocus());

}
AppUtils.closeKeyboard(activity);
if (ButtonUtils.isFastDoubleClick(keyCode)) {
return true;
}
if (TextUtils.isEmpty(editText.getText().toString())) {
return true;
}
// return false;
//让事件延迟流失掉,这样再请求另外的焦点应该不会连锁反应了。
editText.postDelayed(new Runnable() {
@Override
public void run() {

iNotify.onNotify(editText);
}
}, 10);
return true;

} else if (result == 0) {//按键回车按下
return true;

}
return false;
});


editText.setOnEditorActionListener((v, actionId, event) -> {
if (event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_UP) {
return true;
}
if (BaseUtil.isKeyEnterOrHardKeyPress(actionId, event)) {
AppUtils.closeKeyboard(activity);
if (ButtonUtils.isFastDoubleClick(actionId)) {
return true;
}
iNotify.onNotify(editText);
}
return true;
});
}

但是问题依然没解决,

2022-11-26 13:24:13

把抬起改成按下,就可以确保按下的时候百分百是当前的。
这次终于解决了,下班