经反馈,在AndroidTV9.0 盒子上发现EditText一旦获取了焦点之后,遥控器上的方向键就无效了,即焦点无法再转移到其他焦点控件上,但这个问题在Android7.0及以下盒子上却不会出现,应该是Android8.0及以上源码做了修改,故查看EditText源码,得知确实是官方源码对方向键进行了处理~
一、源码分析
EditText源码中搜索onKeyDown
,定位到父类TextView中的onKeyDown()
:
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
final int which = doKeyDown(keyCode, event, null);
if (which == KEY_EVENT_NOT_HANDLED) {
return super.onKeyDown(keyCode, event);
}
return true;
}
很明显doKeyDown()
是关键方法,查看该方法的代码逻辑,主意看注释的部分。
大意:消费掉键盘的箭头事件以防止焦点离开。
private int doKeyDown(int keyCode, KeyEvent event, KeyEvent otherEvent) {
...
if (mMovement != null && mLayout != null) {
...
// Consume arrows from keyboard devices to prevent focus leaving the editor.
// DPAD/JOY devices (Gamepads, TV remotes) often lack a TAB key so allow those
// to move focus with arrows.
if (event.getSource() == InputDevice.SOURCE_KEYBOARD
&& isDirectionalNavigationKey(keyCode)) {
return KEY_EVENT_HANDLED;
}
}
return mPreventDefaultMovement && !KeyEvent.isModifierKey(keyCode)
? KEY_EVENT_HANDLED : KEY_EVENT_NOT_HANDLED;
}
private boolean isDirectionalNavigationKey(int keyCode) {
switch(keyCode) {
case KeyEvent.KEYCODE_DPAD_UP:
case KeyEvent.KEYCODE_DPAD_DOWN:
case KeyEvent.KEYCODE_DPAD_LEFT:
case KeyEvent.KEYCODE_DPAD_RIGHT:
return true;
}
return false;
}
二、自定义EditText
通过上面的源码分析,明确原因之后,解决思路也就很明朗了,即:去掉对键盘方向事件的控制即可。但不管是doKeyDown()
还是isDirectionalNavigationKey()
,这些方法都是私有的,无法通过重写的方式来改变原有逻辑,能重写的只有onKeyDown()
,所以,结合FocusFinder
通过手动查找焦点控件的方式来处理就好了,完整代码如下:
/**
* @author LQR
* @time 2020/3/31
* @desc 解决Android8.0 EditText获取焦点后,无法转换焦点问题
*/
@SuppressLint("AppCompatCustomView")
public class LQREditText extends EditText {
public LQREditText(Context context) {
super(context);
}
public LQREditText(Context context, AttributeSet attrs) {
super(context, attrs);
}
public LQREditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public LQREditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (isDirectKeyCode(keyCode)) {
int direction = FOCUS_DOWN;
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_UP:
direction = FOCUS_UP;
break;
case KeyEvent.KEYCODE_DPAD_DOWN:
direction = FOCUS_DOWN;
break;
case KeyEvent.KEYCODE_DPAD_DOWN_LEFT:
direction = FOCUS_LEFT;
break;
case KeyEvent.KEYCODE_DPAD_RIGHT:
direction = FOCUS_RIGHT;
break;
}
View nextFocus = FocusFinder.getInstance().findNextFocus((ViewGroup) getParent(), this, direction);
if (nextFocus != null) {
nextFocus.requestFocus();
return true;
}
}
return super.onKeyDown(keyCode, event);
}
private boolean isDirectKeyCode(int keyCode) {
return keyCode == KeyEvent.KEYCODE_DPAD_UP
|| keyCode == KeyEvent.KEYCODE_DPAD_DOWN
|| keyCode == KeyEvent.KEYCODE_DPAD_LEFT
|| keyCode == KeyEvent.KEYCODE_DPAD_RIGHT;
}
}
欢迎关注微信公众号:全栈行动
网友评论