导入依赖

Google官方为Android TV的UI开发提供了一系列的规范组件,在leanback的依赖库中,这里介绍一些常用的组件,使用前需要导入leanback库。

implementation 'androidx.leanback:leanback:$version'

常用的页面

这些Fragment有设计好的样式,只需要根据场景选择对应的Fragment,并往里面填充内容即可。

1. BrowseSupportFragment

可以理解为一个水平的tab页面。左边是tab,右边是tab对应的数据。

android tv 网络设置 android tv ui_android tv 网络设置

2. VerticalGridSupportFragment

内部是ViewticalGridView的页面。

android tv 网络设置 android tv ui_动画_02

3. GuidedStepSupportFragment

左边是描述,右边是选项的设置页面。

android tv 网络设置 android tv ui_动画_03

4. ErrorSupportFragment

信息加按钮的页面。

android tv 网络设置 android tv ui_android_04

5. LeanbackSettingsFragment

右侧弹出的设置页面,里面加载一个PreferenceFragment.

android tv 网络设置 android tv ui_android_05

常用组件

1. HorizontalGridView&VerticalGridView

HorizontalGridView和VerticalGridView都继承自RecyclerView,针对TV的特性,在item排版、焦点流转、上/失焦动画、记住焦点、焦点item对齐位置等方面做了比较好的封装。
以HorizontalGridView为例,开发时设计的组件包括:

  • HorizontalGridView:RecyclerView的子类;
  • ArrayObjectAdapter:承担MVP中model的职责,负责提供数据访问接口
  • Presenter:职责类似RecyclerView的adapter,辅助item视图的创建和数据绑定等
  • PresenterSelector:根据不同的数据类型选择不同的Presenter,用于多item type列表模型
  • ItemBridgeAdapter:HorizontalGridView和ObjectAdapter的桥梁,用于解耦双方
  • FocusHighlightHelper:上焦动画帮助类,内置了两种上焦动画
private void initViews() {
        mHgv= (HorizontalGridView) findViewById(R.id.hgv);
        //3行
        mHgv.setNumRows(3);
        //item纵向和横向的距离
        mHgv.setItemSpacing(20);
        //item的对齐方式
        mHgv.setGravity(Gravity.CENTER_VERTICAL);
        //设置
        mHgv.setOnChildViewHolderSelectedListener(new OnChildViewHolderSelectedListener() {
            @Override
            public void onChildViewHolderSelected(RecyclerView parent, RecyclerView.ViewHolder child, int position, int subposition) {
                super.onChildViewHolderSelected(parent, child, position, subposition);
                Log.d(TAG, "onChildViewHolderSelected() returned: " + position);
                //大部分情况下可以通过该方法获取到position
 
            }
 
            @Override
            public void onChildViewHolderSelectedAndPositioned(RecyclerView parent, RecyclerView.ViewHolder child, int position, int subposition) {
                super.onChildViewHolderSelectedAndPositioned(parent, child, position, subposition);
                Log.d(TAG, "onChildViewHolderSelectedAndPositioned() returned: " + position);
                //当通过setSelectedPosition()方法大幅移动列表时,该方法会回调,返回的是最终的真实的position(当set的值超出范围时...)
            }
        });

如果想控制VerticalGridView或者HorizontalGridStyle的焦点是否可以移出去,可以在它的style中设置下面四个属性:

<style name="MyVerticalGridStyle">
        <item name="focusOutFront">true</item>
        <item name="focusOutEnd">false</item>
        <item name="focusOutSideStart">false</item>
        <item name="focusOutSideEnd">true</item>
    </style>

分别对应四个方向,设置为false,表示焦点不能从该方向移到外面,即使在该方向上有能获取焦点的View。如果都为false,那焦点只能在VerticalGridView里面切换了,无法移出到外面。

2. 飞框

智能电视UI需要高亮用户所选中的项来达到导航的效果。 焦点项飞框的动画效果就是飞框会自动移动到下一个选中项,并且会根据下一个选中项的大小进行伸缩变化来包裹高亮下一个选中项。
原理是使用属性动画,获取下一个选中项和当前选中项的位置和宽高等信息,然后使用属性动画和这些信息来动态实现移动飞框View的移动和宽高等动画效果。
Android TV 焦点移动飞框的实现

一些细节

  1. TV开发中,焦点的移动默认是根据系统分配的,但是也可以拦截遥控器的事件,手动分配焦点。
@SuppressLint("RestrictedApi")
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
    if (event.getAction() == KeyEvent.ACTION_DOWN) {
        //当按键按下的时候。
        int keyCode = event.getKeyCode();
        switch (keyCode) {
            case KeyEvent.KEYCODE_DPAD_DOWN:
                ///
                break;
        }
    }

    return super.dispatchKeyEvent(event);
}
  1. View获取焦点的方法是requestFocus()
  2. Android instrumentation是Android系统里面的一套控制方法或者”钩子“。通过Instrumentation可以用来模拟用户的操作,如按键或者点击事件,因此Instrumentation经常被用到测试中