转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52835829

前言:上篇中,《Android TV开发总结(二)构建一个TV Metro界面(仿泰捷视频TV版)》对应的源码解析见《TV Metro界面(仿泰捷视频TV版)源码解析》一文,链接:http://blog.csdn.net/hejjunlin/article/details/52822499,github对应地址:https://github.com/hejunlin2013/TVSample,截至到当前发稿,已突破200star,如果喜欢的话,可以star,也表示下支持,今天主要总结下TV开发中有焦点问题。

在TV开发中没有以前我们phone端的dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent 事件来分发,而需要使用dispatchKeyEvent、onKeyDown、onKeyLisenter 等事件来分发处理焦点事件传递,而且TV端焦点没有什么好办法可以全局控制,需要我们自己来想办法规定焦点走向,可以参考我的View焦点总结《Android View框架总结(二)View焦点》,本篇做应用场景补充说明及遇到有坑,看下Agenda:

  • 采用Android自带的直接控制焦点上下左右
  • 采用setOnFocusChangeListener控制焦点
  • adb按键派发控制焦点
  • 遇到的坑-遥控器按键失灵案列

Android TV 开发与一般Android开发最大的区别在于焦点控制 , 用户在使用Android TV设备主要是通过遥控器操作app。焦点就是让用户知道的直接交互行为。 然而一些app,依据系统对focus的判断,会出现的状况: 上下导航时,不是想要的结果. 边缘移动时,会出现焦点丢失的状况. 有时想直接定位到某个位置上.

android提供了一些焦点相关的属性,在现有的框架层下通过设置View的属性来获得焦点





下面列出三种方法处理焦点问题

一、采用Android自带的直接控制焦点上下左右的方法

采用Android自带的直接控制焦点上下左右的方法

因此在进行布局时有必须要通过view.setId(…)指定view的特定ID,然后通过view.setNextLeftView(…)等四个方法控制该view的上下左右移动后所到达的view。然而这种方法只适用于前提就设置好ID的场景,不适合动态布局的场景。

看如下一段布局:





rg_a1,rg_a2,rg_a3,rg_a4实际业务中会写明其含义,而不是a1,a2之类,这里只是为介绍,这个自定义的MyCustomButton,按遥控器左键时,将找id为rg_a1的view,焦点跳过去,按遥控器右键时,将找id为rg_a2的view,焦点跳过去,按遥控器下键时,将找id为rg_a3的view,焦点跳过去,按遥控器上键时,将找id为rg_a5的view,焦点跳过去。

二、采用setOnFocusChangeListener控制焦点

看如下一段代码:





当OnFocusChangeListener时,就是从一个焦点跳到另一个view上的变化过程。

三、adb按键派发控制焦点

按键的派发须了解一此KeyCode,下面是平时用到的主要的一些方向键:





在按键过程中 按下和松开的Action主要是ACTION_DOWN、ACTION_UP事件分发和处理是在ACTION_DOWN中处理

当设置View.setFocusable(true); 改变控件是否可以获得焦点,然而同时会触发 setOnFocusChangeListener事件

在adb中,可以通过注入的方式模拟按键,如 adb shell input keyevent 3 给示模拟Home键

以下是的KEYCODE供参考:

KEYCODE_UNKNOWN=0;
KEYCODE_SOFT_LEFT=1;
KEYCODE_SOFT_RIGHT=2;
KEYCODE_HOME=3;
KEYCODE_BACK=4;
KEYCODE_CALL=5;
KEYCODE_ENDCALL=6;
KEYCODE_0=7;
KEYCODE_1=8;
KEYCODE_2=9;
KEYCODE_3=10;
KEYCODE_4=11;
KEYCODE_5=12;
KEYCODE_6=13;
KEYCODE_7=14;
KEYCODE_8=15;
KEYCODE_9=16;
KEYCODE_STAR=17;
KEYCODE_POUND=18;
KEYCODE_DPAD_UP=19;
KEYCODE_DPAD_DOWN=20;
KEYCODE_DPAD_LEFT=21;
KEYCODE_DPAD_RIGHT=22;
KEYCODE_DPAD_CENTER=23;
KEYCODE_VOLUME_UP=24;
KEYCODE_VOLUME_DOWN=25;
KEYCODE_POWER=26;
KEYCODE_CAMERA=27;
KEYCODE_CLEAR=28;
KEYCODE_A=29;
KEYCODE_B=30;
KEYCODE_C=31;
KEYCODE_D=32;
KEYCODE_E=33;
KEYCODE_F=34;
KEYCODE_G=35;
KEYCODE_H=36;
KEYCODE_I=37;
KEYCODE_J=38;
KEYCODE_K=39;
KEYCODE_L=40;
KEYCODE_M=41;
KEYCODE_N=42;
KEYCODE_O=43;
KEYCODE_P=44;
KEYCODE_Q=45;
KEYCODE_R=46;
KEYCODE_S=47;
KEYCODE_T=48;
KEYCODE_U=49;
KEYCODE_V=50;
KEYCODE_W=51;
KEYCODE_X=52;
KEYCODE_Y=53;
KEYCODE_Z=54;
KEYCODE_COMMA=55;
KEYCODE_PERIOD=56;
KEYCODE_ALT_LEFT=57;
KEYCODE_ALT_RIGHT=58;
KEYCODE_SHIFT_LEFT=59;
KEYCODE_SHIFT_RIGHT=60;
KEYCODE_TAB=61;
KEYCODE_SPACE=62;
KEYCODE_SYM=63;
KEYCODE_EXPLORER=64;
KEYCODE_ENVELOPE=65;
KEYCODE_ENTER=66;
KEYCODE_DEL=67;
KEYCODE_GRAVE=68;
KEYCODE_MINUS=69;
KEYCODE_EQUALS=70;
KEYCODE_LEFT_BRACKET=71;
KEYCODE_RIGHT_BRACKET=72;
KEYCODE_BACKSLASH=73;
KEYCODE_SEMICOLON=74;
KEYCODE_APOSTROPHE=75;
KEYCODE_SLASH=76;
KEYCODE_AT=77;
KEYCODE_NUM=78;
KEYCODE_HEADSETHOOK=79;
KEYCODE_FOCUS=80;//*Camera*focus
KEYCODE_PLUS=81;
KEYCODE_MENU=82;
KEYCODE_NOTIFICATION=83;
KEYCODE_SEARCH=84;
KEYCODE_MEDIA_PLAY_PAUSE=85;
KEYCODE_MEDIA_STOP=86;
KEYCODE_MEDIA_NEXT=87;
KEYCODE_MEDIA_PREVIOUS=88;
KEYCODE_MEDIA_REWIND=89;
KEYCODE_MEDIA_FAST_FORWARD=90;
KEYCODE_MUTE=91;

  • 问题描述:播放中出现屏保,从屏保回到某页面后,遥控器失灵。从某页进入全屏播放,暂停,等小米的屏保出来后将屏保消失,返回到某页面继续播放。此时遥控器方向键、确定键均无响应。Home键、电源键有响应。菜单键有响应。

    分析:没有响应,按键被拦截,查了下当时改动的代码时,对按键并未做特殊拦截…. 对比之前的版本,没有这个问题。确认问题出现在浮层…从log中看,onWindowFocusChanged,在从h5界面/屏保界面回到某页面,没有被调用。

    说明从window到activity这层,按键就被吃掉了。

  • 接着分析:整个BaseActivity,没有接收到Action_Down事件

    Log中打印的“Dropping event due to no window focus”,思路又断了。

    继续做对比,发现show出浮层时,没有任何异常,但是只要show时,焦点移动,就能复现按键不响应。最后就定位到一个自定义控件上

  • 再接着分析:这个控件1600多行代码,最初一直在找之前版本改动的地方区别,之前版本主要是做一些对这个控件的定制化,其他的先不考虑,排除法,找和event相关的方法。dispatchKeyEvent没有任何异常,又没有思路了,既然是系统级别的传递过程中就被吃了,会不会和view相关,因为只要焦点移动,就失灵,焦点移动伴随着,有一个popupwindow弹出,最终定位在onAttachWindow,好像也没有做什么特殊的事,用了一个getHandler,起初我以为是个自己写的方法,追点进去getHandler一看,是View的



  • 问题修复:

    总结:用View的Handler以前是为处理popupwindow时,popupwindow通过post的方式去show,但是如果此时activity ondestory则会导致出错,所以加了onDetachWindow和onAttachWindow,原因主要是在onDetachWindow时,mHandler.removeCallbacksAndMessages(null);这句话导致,它相当于是把window发给View这层message给移除了。最后修改只移除它对应的的runnable,问题修复。



第一时间获得博客更新提醒,以及更多android干货,源码分析,欢迎关注我的微信公众号,扫一扫下方二维码或者长按识别二维码,即可关注。





如果你觉得好,随手点赞,也是对笔者的肯定,也可以分享此公众号给你更多的人,原创不易

Android TV开发总结(三)构建一个TV app的焦点控制及遇到的坑的更多相关文章

  1. Android TV开发总结(六)构建一个TV app的直播节目实例

    请尊重分享成果,转载请注明出处:http://blog.csdn.net/hejjunlin/article/details/52966319 近年来,Android TV的迅速发展,传统的有线电视受 ...

  2. Android TV开发总结(七)构建一个TV app中的剧集列表控件

    原文:Android TV开发总结(七)构建一个TV app中的剧集列表控件 版权声明:我已委托"维权骑士"(rightknights.com)为我的文章进行维权行动.转载务必转载 ...

  3. Android ROM开发(三)——精简官方ROM并且内置ROOT权限,开启Romer之路

    Android ROM开发(三)--精简官方ROM并且内置ROOT权限,开启Romer之路 相信ROM的相关信息大家通过前几篇的学习都是有所了解了,这里就不在一一提示了,这里我们下载一个官方包,我们还 ...

  4. Android UI开发第三十九篇——Tab界面实现汇总及比较

    Tab布局是iOS的经典布局,Android应用中也有大量应用,前面也写过Android中TAb的实现,<Android UI开发第十八篇——ActivityGroup实现tab功能>.这 ...

  5. 《Android Studio开发实战 从零基础到App上线》资源下载和内容勘误

    转载于:https://blog.csdn.net/aqi00/article/details/73065392 资源下载 下面是<Android Studio开发实战 从零基础到App上线&g ...

  6. Android TV开发总结(四)通过RecycleView构建一个TV app列表页(仿腾讯视频TV版)

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52854131 前言:昨晚看锤子手 ...

  7. Android TV开发总结(一)构建一个TV app前要知道的事儿

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52792562 前言:近年来,智能 ...

  8. Android TV开发总结(五)TV上屏幕适配总结

    前言:前面几篇总结一些TV上的小Sample,开源到GitHub:https://github.com/hejunlin2013/TVSample, 点击链接,可以持续关注.今天总结下TV上屏幕适配. ...

  9. 安卓TV开发(三) 移动智能设备之实现主流TV电视盒子焦点可控UI

    前言:移动智能设备的发展,推动了安卓另一个领域,包括智能电视和智能家居,以及可穿戴设备的大量使用,但是这些设备上的开发并不是和传统手机开发一样,特别是焦点控制和用户操作体验上有很大的区别,本系列博文主 ...

随机推荐

  1. 40叔:自学的伙伴推荐看的PHP视频和书藉

    记录一下我的学习编程经历,在自学的路上,看了不少的断断续续的看了不少的视频,现在只会一点PHP增删改查. 同样迷的有没有? 要自己用原生的开发个CMS 或者BBS,ask 系统好像还差的远. 所以回头 ...

  2. laydate 日期格式为yyyy 或yyyy-MM时,出现错误Uncaught TypeError: Cannot read property 'length' of undefined

    这个改起比较麻烦,没有深究,简单兼容了yyyy 和yyyy-MM,其他格式可能还是会有错误.替换Dates.check方法. //检测日期是否合法 Dates.check = function(){ ...

  3. 0418 jQuery笔记(添加事件、each、prop、$(this))

    1.添加点击事件.each.prop.$(this) //全选框的被动操作 //定义一个标志保存最终状态 var flag = false; //为每一个选择框添加点击事件,数组.click() $( ...

  4. hive新特性reflect函数介绍

    reflect函数可以支持在sql中调用java中的自带函数,秒杀一切udf函数. 使用案例1:所有记录执行相同的java内置函数 hive中建一张表test_udf:column1(int),col ...

  5. pwd

    显示当前在文件系统里的确切位置 注: 系统根目录是/ 用户主目录是/home/用户名 对于root用户,用户主目录为/root

  6. [Ioi2011]ricehub

    Description 乡间有一条笔直而长的路称为“米道”.沿着这条米道上 R 块稻田,每块稻田的坐标均 为一个 1 到 L 之间(含 1 和 L)的整数.这些稻田按照坐标以不减的顺序给出,即对于 0 ...

  7. 矩阵树Matrix-Tree定理与行列式

    简单入门一下矩阵树Matrix-Tree定理.(本篇目不涉及矩阵树相关证明) 一些定义与定理 对于一个无向图 G ,它的生成树个数等于其基尔霍夫Kirchhoff矩阵任何一个N-1阶主子式的行列式的绝 ...

  8. 「LibreOJ NOIP Round #1」旅游路线

    Description T 城是一个旅游城市,具有 nnn 个景点和 mmm 条道路,所有景点编号为 1,2,...,n1,2,...,n1,2,...,n.每条道路连接这 nnn 个景区中的某两个景 ...

  9. 2015 多校联赛 ——HDU5400(水)

    Sample Input 5 2 -2 0 2 0 -2 0 5 2 3 2 3 3 3 3   Sample Output 12 5 求最多多少序列满足,前半部分满足d(j+1) = d(j)+d1 ...

  10. ubuntu16.04安装eclipse后启动栏图标为问号

    ubuntu创建eclipse快捷方式图标. cd /usr/share/applications sudo touch eclipse.desktop sudo gedit eclipse.desk ...