简书链接:关于按键回车改变焦点为其他编辑框引发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
把抬起改成按下,就可以确保按下的时候百分百是当前的。 这次终于解决了,下班