Andriod TV开发之Leanback

6,320 阅读4分钟
原文链接: my.oschina.net

本人由于最近一段时间很忙,一直都没有更新 android tv的开源库了,因为技术的更新迭代,TV开发的库已经升级为Leanback + 移动边框等等东西,希望这篇文章能激发你对于 Android TV 更多的想法,水平有限,互相学习,谢谢.

Android tv 开源社区地址:https://gitee.com/kumei (欢迎加入)

Android tv 开源社区收集的库:https://gitee.com/kumei/Android_tv_libs

Leanback demo地址: https://github.com/googlesamples/leanback-showcase

 

谷歌官方的 demo 中 是这样的,那样的... ...,都是围绕 Fragment展开的.

如果真不想用谷歌自带的Fragment,想单独使用,或者写自己的标题栏或者多级菜单,这么办?

先来一张图片,类似下图的布局确实很酷炫.

 

如何使用 Leanback 的库

  • 直接Adnroid studio 导入,版本有差异化,不懂的百度查,github看.

使用Leanback弄出下面的界面

我感觉不用分析什么Leabnack,也不用讲解一大堆如何使用,我下面就直接贴代码,并注释吧.

先来分析下上图,标题栏 + ViewPager(包含多个Fragment)

如果标题栏使用 Recyclerview 或者横向的布局,你都要处理焦点记忆问题,

这里推荐使用 Leanback 的 HorizontalGridView 作为标题栏使用,已经帮你处理焦点记忆问题,并且很不错.

标题栏

xml 大概如下 布局如下

<!-- 影视标题栏 -->
<com.open.leanback.widget.HorizontalGridView
            android:id="@+id/****"
            android:layout_width="match_parent"
            android:layout_height="@dimen/title_h" />

 <!-- 影视内容 -->
<android.support.v4.view.ViewPager
            android:id="@+id/*****"
            android:layout_weight="1"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

HorizontalGridView 其实继承的 RecyclerView,使用方式是一样的.

        mTitlerAdapter = new TitlerAdapter();
        titleHgridview.setAdapter(mTitlerAdapter);
        // 进行强转,GridLayoutManager.
        ((GridLayoutManager)titleHgridview.getLayoutManager()).setOnChildSelectedListener(new OnChildSelectedListener() {
            @Override
            public void onChildSelected(ViewGroup parent, View view, int position, long id) {
               // 选中某个item的处理, 比如翻页等等操作
            }
        });

这里给大家介绍一个小技巧 android:duplicateParentState="" 的使用,再配合 selector,然后布局里面的 控件都可以获取到父布局的属性,爽歪歪.

ViewPager内容

  •  布局里面使用 VerticalGridView,这里就相当使用 GridView,类似下图.

        mMoviceAdapter = new MoviceAdapter();
        moviceVgridview.setAdapter(mMoviceAdapter);
        // 初始化影视垂直布局.
        moviceVgridview.setNumColumns(6);
         // 因为标题下面布局的焦点上不去标题栏,需要设置,具体原理参考源码.
        ((GridLayoutManager)moviceVgridview.getLayoutManager()).setFocusOutAllowed(true, true);
        ((GridLayoutManager)moviceVgridview.getLayoutManager()).setOnChildSelectedListener(new OnChildSelectedListener() {
            @Override
            public void onChildSelected(ViewGroup parent, View view, int position, long id) {
            }
        });


// FocusOutAllowed focusOutSidAl... 也可以再xml设置,设置的属性如下,具体参考谷歌demo
<declare-styleable name="lbBaseGridView"> 
    <attr name="focusOutFront" format="boolean"/>
    <attr name="focusOutEnd" format="boolean"/> 
    <attr name="focusOutSideStart" format="boolean"/> 
    <attr name="focusOutSideEnd" format="boolean"/> 
    <attr name="horizontalMargin" format="dimension"/> 
    <attr name="verticalMargin" format="dimension"/> 
    <attr name="android:gravity"/>
</declare-styleable>
  • 如果想实现复杂的带标题栏的布局,类似下面的,或者小米瀑布流的.

// 使用 Leanback下列的数据结构,设置的方式和 Recyclerview差不多,具体也可以参考 Leabanck 的谷歌demo.

ItemBridgeAdapter mItemBridgeAdapter;
mVerticalGridView.setAdapter(mItemBridgeAdapter);

// 测试数据,demo.

public ItemBridgeAdapter getMoviceItemDatas() {
        mItemBridgeAdapter = new ItemBridgeAdapter();
        CardPresenter cardPresenter = new CardPresenter();
        final NewPresenterSelector newPresenterSelector = new NewPresenterSelector();
        ArrayObjectAdapter mRowsAdapter = new ArrayObjectAdapter(newPresenterSelector); // 填入Presenter选择器.
        for (int i = 0; i < 100; i++) {
            ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
            MoviceItemData moviceItemData = mMoviceItemData.get(i); // 包含标题+内容列表的数据
            String title = moviceItemData .getTitle();
            HeaderItem settingHeader = new HeaderItem(i, title); // 标题头(比如 xxx榜单)
            List<SettingItem> items = moviceItemData.getItems(); // 内容列表.(影视内容)
            // 小技巧: 比如需要像图片中的频道一样,这里服务端返回的数据很多,换行了,
            // 可以进数据分段,一行8个填入,最后一行的,设置 ListRow(null, listRowAdapter2),那么标题栏就没有了.
            //
            ArrayObjectAdapter listRowAdapter2 = new ArrayObjectAdapter(cardPresenter);
            listRowAdapter2.addAll(0, items);
            ListRow listRow2 = new ListRow(settingHeader, listRowAdapter2);
            mRowsAdapter.add(listRow2);
        }
        mItemBridgeAdapter.setAdapter(mRowsAdapter);
        return mItemBridgeAdapter;
}

PresenterSelector 选择器,具体可以参考谷歌demo.

public class NewPresenterSelector extends PresenterSelector {
    private AListRowPresenter mNewListRowPresenter = new AListRowPresenter();
    private ARowPresenter mNewListRowPresenter2 = new AListRowPresenter();

    public NewPresenterSelector() {
    }

    @Override
    public Presenter getPresenter(Object item) {
        // 根据item判断,加载相应的 presenter,这里主要为了显示不同的东西.
    }

    @Override
    public Presenter[] getPresenters() {
        return new Presenter[]{
                *** ***
        };
    }
}

 

如何添加按键加载更多

由于TV上面属于遥控器操作,不像手机上面那样.

 @Override
    public void onScrollStateChanged(int state) {
        if (state == SCROLL_STATE_IDLE) {
           
            if (getLastVisiblePosition() >= getAdapter().getItemCount() - 1) {
                // 加载更多
            }
        }
        super.onScrollStateChanged(state);
}


public int getLastVisiblePosition() {
        final int childCount = getChildCount();
        if (childCount == 0)
            return 0;
        else
            return getChildAdapterPosition(getChildAt(childCount - 1));
}

// 也可以再这里进行处理,具体看需求了,还有个人喜好.
 @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        return super.dispatchKeyEvent(event);
    }

如何适配不同分辨率

我这里使用的是 AutoLayout,我以前也写过一篇文章 android tv如何适配不同平台,这里就不过多废话了.

 

放大效果

 

 

配合移动边框边框使用

 

性能优化

 

有空后续整理到文章,笔记更新处:b53aa9d9.wiz03.com/share/s/2Re…