Skip to content

msisuzney/tv-waterfall-layout

Repository files navigation

Android TV瀑布流控件

一种基于Android Leanback改造的Android TV瀑布流布局

示例效果如下:

演示

解决的问题

瀑布流布局的运营按照栏目划分,每个栏目中的资源、海报宽高完全按运营需要自定义, 但Leanback不支持自定义栏目中的View的宽高、栏目中的View居中

特性

  • 做为瀑布流布局的运营单元,行的布局可以是HorizontalGridView或者ColumnLayout,也可以自定义的布局
  • 获得焦点的View自动居中显示
  • 快速滑动时不会出现焦点移动不合理的情况
  • 支持焦点自动换行,使用FocusLineFeedFrameLayout作为子View的根布局,当焦点在屏幕右边缘时按下右键,焦点会换行到下一行的第一个View,左边缘同理换行到上一行最后一个View
  • ColumnLayout栏目中的子View可以实现ColumnFocusChangeListener监听整个栏目的焦点变化
  • 栏目中的View可以通过实现StateChangedObserver接口,并将自己注册给StateChangeObservable,以便监听RecyclerView的滑动状态

以上所有特性都在demo中演示

使用

1.设计理念

延用了Leanback中的Model -> Presenter -> View的理念:

演示

Presenters根据不同的Bean创建不同的View,具体见android/tv-samples

2.使用方式

  1. 添加依赖
//1) 根目录下build.gradle
allprojects {
    repositories {
        //add jitpack.io repo
        maven { url 'https://jitpack.io' }
    }
}

//2) module build.gradle
dependencies {
    //add lib
    implementation 'com.github.msisuzney:tv-waterfall-layout:1.0.1'
}
  1. 继承RowsFragment
  2. 添加ColumnLayout布局栏目,使用ColumnLayoutCollection定义栏目的宽高,再使用ColumnLayoutItem定义子View的位置、大小、bean类型与数据, 最后使用setItems方法将ColumnLayoutItems添加到ColumnLayoutCollection
  3. 添加水平滑动的HorizontalGirdView布局栏目,使用HorizontalLayoutCollection定义栏目的宽高,再使用HorizontalLayoutItem定义子View的大小、bean类型与数据, 最后使用setItems方法将HorizontalLayoutItems添加到HorizontalLayoutCollection
  4. 使用RowsFragment#add方法将ColumnLayoutCollection/HorizontalLayoutCollection添加到布局中
  5. 复写RowsFragment#initBlockPresenterSelector方法,返回的PresenterSelector用于根据bean类型为栏目创建不同的View

详细使用见demo module代码,简易代码如下:

public class MyFragment extends RowsFragment {


    @Override
    protected PresenterSelector initBlockPresenterSelector() {
        //1.提供所有行中的运营位的Presenters,用于创建对应的View
        return new PresenterSelector() {
            @Override
            public Presenter getPresenter(Object item) {
                return new ImageViewPresenter(null);
            }
        };
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        //2. 构造水平滑动布局的Model
        HorizontalLayoutItem item = new HorizontalLayoutItem();
        item.setWidth(200);
        item.setHeight(200);
        List<HorizontalLayoutItem> items = new ArrayList<>();
        items.add(item);
        HorizontalLayoutCollection horizontalLayoutCollection =
                new HorizontalLayoutCollection(ViewGroup.LayoutParams.MATCH_PARENT, 200);
        horizontalLayoutCollection.setItems(items);

        //3. 构造绝对布局的Model
        AbsoluteLayoutItem item1 = new AbsoluteLayoutItem();
        item1.setHeight(200);
        item1.setWidth(200);
        item1.setX(200);
        item1.setY(10);
        List<AbsoluteLayoutItem> items1 = new ArrayList<>();
        items1.add(item1);
        AbsoluteLayoutCollection absoluteLayoutCollection =
                new AbsoluteLayoutCollection(ViewGroup.LayoutParams.MATCH_PARENT, 400);
        absoluteLayoutCollection.setItems(items1);
        
        //4. 添加到布局中
        add(horizontalLayoutCollection);
        add(absoluteLayoutCollection);
    }
}