Android TV焦点控制逻辑

本文详细探讨了Android TV的焦点控制逻辑,包括简单的焦点控制属性设置、Event事件机制,特别是按键事件的dispatchKeyEvent()执行流程,以及焦点查找方法focusSearch()和findNextFocus()。在按键焦点查找流程中,解释了界面首次获取焦点以及按键操作下焦点的移动过程。
摘要由CSDN通过智能技术生成

1. 首先简单的焦点控制在对应的布局控件里设置如下属性:

android:nextFocusUp="@id/下一个控件的id"
android:nextFocusDown=""
android:nextFocusLeft=""
android:nextFocusRight=""

分别对应该控件按下↑、↓、←、→键对应的下一个控件。

2.焦点控制逻辑:

翻看各大博客,对与AndroidTV焦点控制的理解都大同小异,接下来是我对与焦点控制的理解:

2.1Event事件机制:

在哪些对象中进行的:

Activity -> Window -> ViewGroup -> View

包含拦截、分发、响应:

拦截发生在: onInterceptTouchEvent()方法中,当用户触发event事件后,由上层传入,当此方法返回true时,则被拦截不会继续往子view传递,由当前view的 onTouchEvent()来响该事件。

                                                                                                                                                               返回false时,不会被拦截,事件将继续传递  ,由子view调用当前view的 dispatchTouchEvent()  去分发, 最后由具体的控件去消费此事件。

分发:

   dispatchEvent(MotionEvent event)  负责事件的调度,很多人称之为分发和传递也一个意思,主要负责将事件交由哪个控件去处理,如果自己不想处理,则可以继续往下传递,想处理则触发本身view的ontuchEvent(),

   此方法也返回boolean类型,返回ture代表传递,返回false代表不传递,和我们的事件拦截恰恰相反,对于初学者来说很容易搞糊涂,本事件Activty,ViewGroup,View都拥有处理权,主要将事件负责转发,无论交由别人处理还是自己,其实都在充当调度角色,是事件的核心。

响应(消费):

  安卓中事件具体处理由 onTouchEvent()  来执行,此阶段主要负责事件的消费响应,通过处理完事件后,然后逐步向上级汇报,如果消费了上级则不会再进行做响应消费处理,只会继续返回给根布局。

  此方法返回布尔类型,如果消费了此事件,则会调用上级的此方法,默认返回false做处理,如果返回true,则代表不消费此时间 ,让上级调用本方法去做处理,逐步网上汇报,直到Activity得到消息为止。

过程:

 如图A:代表activity,B:代表ViewGroup(如:布局),C:代表View(如:button)

点击屏幕上的C时整个事件将会由A—B --C —B—A这样的顺序进行分发。

具体情况如下:

 当点击C (Button)时,首先有A进行分发,然后传递到B,如果B不拦截,则继续分发,传递到C ,此时C无法继续传递 ,则执行事件,消费后继续向上反馈,

上级则不会进行消费处理,如果不消费,

则由上级B(Layout)进行处理,如果不处理,则继续交由A(Activity)处理,此时此事件结束。

2.2按键事件:

KeyEvent:位于android.view下,KeyEvent主要有以下事件类型:

   KeyEvent.KEYCODE_DPAD_UP; 上
   KeyEvent.KEYCODE_DPAD_DOWN; 下
   KeyEvent.KEYCODE_DPAD_LEFT;左
   KeyEvent.KEYCODE_DPAD_RIGHT;右
   KeyEvent.KEYCODE_DPAD_CENTER;确定键
   KeyEvent.KEYCODE_DPAD_RIGHT; 右
   KeyEvent.KEYCODE_XXX:数字键 (xx表示你按了数字几)
   KeyEvent.KEYCODE_BACK; 返回键
   KeyEvent.KEYCODE_HOME;房子键

   KeyEvent.KEYCODE_A: A-Z,26个字母

   KeyEvent.KEYCODE_MENU菜单键。

首先看事件分发图:

如上图:

首先,KeyEvent会流转到ViewRootImpl中开始进行处理,具体方法是内部类ViewPostImeInputStage中的processKeyEvent。

代码如下:

复制代码

private int processKeyEvent(QueuedInputEvent q) {
        final KeyEvent event = (KeyEvent)q.mEvent;
        ...
        // Deliver the key to the view hierarchy.
        // 1. 先去执行mView的dispatchKeyEvent
        if (mView.dispatchKeyEvent(event)) {
            return FINISH_HANDLED;
        }
        ...
        // Handle automatic focus changes.
        if (event.getAction() == KeyEvent.ACTION_DOWN) {
            int direction = 0;
            ...
            if (direction != 0) {
                View focused = mView.findFocus();
                if (focused != null) {
                    // 2. 之后会通过focusSearch去找下一个焦点视图
                    View v = focused.focusSearch(direction);
                    if (v != null && v != focused) {
                        ...
                        if (v.requestFocus(direction, mTempRect)) {
                            ...
                            return FINISH_HANDLED;
                        }
                    }

                    // Give the focused view a last chance to handle the dpad key.
                    if (mView.dispatchUnhandledMove(focused, direction)) {
                        return FINISH_HANDLED;
                    }
                } else {
                    // find the best view to give focus to in this non-touch-mode with no-focus
                    // 3. 如果当前本来就没有焦点视图,也会通过focusSearch找一个视图
                    View v = focusSearch(null, direction);
                    if (v != null && v.requestFocus(direction)) {
                        return FINISH_HANDLED;
                    }
                }
            }
        }
        return FORWARD;
    }

复制代码

看上面的代码可以了解:

      先执行mView的dispatchKeyEvent()方法,再通过focusSearch()去找下一个焦点视图,如果当前没由焦点视图也会执行focusSearch()找一个视图。

2.2.1 dispatchKeyEvent()执行流程

    DecorView →Activity→ViewGroup→view。

DecorView 的 dispatchKeyEvent ():

复制代码

public boolean dispatchKeyEvent(KeyEvent event) {
    ... ...
    if (!mWindow.isDestroyed()) {
        // Activity实现了Window.Callback接口,具体可以参考 Activity.java 源码.
        final Window.Callback cb = mWindow.getCallback();
        // mFeatureId < 0,表示为 application 的 DecorView.
        // cb.dispatchKeyEven 调用的是 Activity 的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值