开发TV应用与开发手机应用的最大不同就是焦点
关键方法梳理
- 触摸模式
- 关键方法
- View.setFocusable
- View.setFocusableInTouchMode
- View.hasFocus
- View.hasFocusable
- View.setOnFocusChangeListener
- View.focusSearch
- View.findFocus
- View.requestFocus
- View.clearFocus
- View.addFocusables
- ViewGroup.findFocus
- ViewGroup.clearFocus
- ViewGroup.requestFocus
- ViewGroup.onRequestFocusInDescendants
- ViewGroup.getFocusedChild
- ViewGroup.focusSearch
Android中分为触摸模式1和选择模式
通常在手机、平板等触摸屏设备上默认都会处于触摸模式。
Android当中提供了View.isInTouchMode方法来判断当前的设备是否处于触摸模式。当我们使用adb命令向设备发送方向键事件时,设备就会进入选择模式
View.setFocusable
设置focusable为true时将会给View添加对应的flag
View.setFocusableInTouchMode
设置触摸模式可聚焦即可在触摸模式下可聚焦,有同学可能会发现recyclerView跟其他控件嵌套使用,有时会抢占焦点,就是因为设置了这个标记的缘故
View.hasFocus
如果此视图本身有焦点,或者它的子视图有焦点,则返回true
View.hasFocusable
如果此视图可聚焦,或者它的子视图可聚焦,则返回true,注意只有Visibility为visiable的才算
View.setOnFocusChangeListener
这个方法会在视图的焦点状态被更改时调用,这个方法有对应的get方法
View.focusSearch
这个方法会调用ViewGroup的双参数方法,将自己作为起点,向特定的方向搜索下一个焦点,当然了,前提是这个视图被添加到一个ViewGroup中
View.findFocus
此视图本身是否已聚焦,是返回自己,否则返回null
View.requestFocus
无参方法会调用到requestFocusNoSearch方法
因为View不需要去检查子视图是否需要获得焦点,所以满足条件后会直接获得焦点
View.clearFocus
此方法会清除视图的焦点,注意此方法清除焦点后,如果系统处于选择模式,清除焦点后会丢失焦点,那么焦点会跑到左上角第一个可聚焦的视图,大屏tv开发时不建议调用此方法
View.addFocusables
此方法会在FocusFinder查找焦点时调用,用于从ViewGroup中收集可聚焦的视图,如果是View就是收集View本身
ViewGroup.findFocus
View的同名重载方法,如果此ViewGroup已经聚焦则返回自己,如果它的子视图已聚焦,则会调用子视图的同名方法
需要注意的是,这里的mFocused指的是当前ViewGroup的直接子视图,而返回值返回的是真正聚焦的视图
ViewGroup.clearFocus
此ViewGroup会先清除自己或者子视图的焦点
ViewGroup.requestFocus
这里涉及到descendantFocusability这个关键方法
我们可以在xml中设置这个属性,值分别时
- blocksDescendants(阻止后代获取焦点,父视图直接获得焦点)
- beforeDescendants(在后代之前获得焦点,如果父视图能获得焦点,父视图会直接获得焦点,否则会调用onRequestFocusInDescendants把焦点分发给子视图)
- afterDescendants(在后代之后获得焦点,先调用onRequestFocusInDescendants把焦点分发给子视图,如果子视图不能获得焦点那么发给自己)
此方法会检查
ViewGroup.onRequestFocusInDescendants
当你对此ViewGroup进行requestFocus时根据你设置的descendantFocusability会看情况自动调用,
你可以重写此方法来定义你的ViewGroup寻找子视图的规则
ViewGroup.getFocusedChild
直接返回已经聚焦的子视图,与findFocus不同的是findFocus会按照层级寻找已聚焦的子视图
ViewGroup.focusSearch
这个方法会检查是否是根视图,是根视图就会调用FocusFinder查找焦点,否则就会请求父视图查找焦点,可以重写此方法更新搜索策略,例如recyclerView
- https://android-developers.googleblog.com/2008/12/touch-mode.html ↩︎