Android开发经验谈Android技术知识Android开发

AndroidTV——解决EditText焦点无法转移问题

2020-03-31  本文已影响0人  GitLqr

经反馈,在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;
    }
}

欢迎关注微信公众号:全栈行动
上一篇 下一篇

猜你喜欢

热点阅读