一种基于Android Leanback改造的Android TV瀑布流布局
示例效果如下:
瀑布流布局的运营按照栏目划分,每个栏目中的资源、海报宽高完全按运营需要自定义, 但Leanback不支持自定义栏目中的View的宽高、栏目中的View居中
- 以
行
做为瀑布流布局的运营单元,行的布局可以是HorizontalGridView
或者ColumnLayout
,也可以自定义行
的布局 - 获得焦点的
View
自动居中显示 - 快速滑动时不会出现焦点移动不合理的情况
- 支持焦点自动换行,使用
FocusLineFeedFrameLayout
作为子View的根布局,当焦点在屏幕右边缘时按下右键,焦点会换行到下一行的第一个View
,左边缘同理换行到上一行最后一个View
ColumnLayout
栏目中的子View
可以实现ColumnFocusChangeListener
监听整个栏目的焦点变化- 栏目中的
View
可以通过实现StateChangedObserver
接口,并将自己注册给StateChangeObservable
,以便监听RecyclerView
的滑动状态
以上所有特性都在demo中演示
延用了Leanback中的Model -> Presenter -> View
的理念:
Presenters根据不同的Bean创建不同的View,具体见android/tv-samples
- 添加依赖
//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'
}
- 继承
RowsFragment
- 添加
ColumnLayout
布局栏目,使用ColumnLayoutCollection
定义栏目的宽高,再使用ColumnLayoutItem
定义子View
的位置、大小、bean类型与数据, 最后使用setItems
方法将ColumnLayoutItems
添加到ColumnLayoutCollection
中 - 添加水平滑动的
HorizontalGirdView
布局栏目,使用HorizontalLayoutCollection
定义栏目的宽高,再使用HorizontalLayoutItem
定义子View
的大小、bean类型与数据, 最后使用setItems
方法将HorizontalLayoutItems
添加到HorizontalLayoutCollection
- 使用
RowsFragment
#add
方法将ColumnLayoutCollection
/HorizontalLayoutCollection
添加到布局中 - 复写
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);
}
}