阅读自:Android 复杂的列表视图新写法 MultiType
1、实现线性布局和网格布局混排列表 的讲解
效果图
为了实现如上图的线性和网格的混合视图效果,只需要一个 GridLayoutManager
(其继承自 LinearLayoutManager
)而关键的代码就是下图中的为 GridLayoutManager
设置 GridLayoutManager.SpanSizeLookup
监听器: GridLayoutManager.SpanSizeLookup
的 getSpanSize()
方法返回的就是当前 position
位置的 item 所占的网格数。在这里,当 Item 对应为 特别篇\本篇
一栏时,因为效果上该栏需要占一整行,所以当判定为该栏时,就返回 5 ,表示该栏需要占 5 个网格的宽度。,而每一行总共 5 个网格,即会占满整行。
2、实现 RecyclerView 嵌套横向 RecyclerView
如果是要实现竖向的 RV 里面嵌套一个横向的 RV ,则只需要把横向的 RV 当作一个特殊的 Item 即可,实现起来主要有以下几个步骤:
(1)首先定义横向的 RV 的 Item 的布局文件,假设名为 item_hor_list_item.xml
,且内部就是一个简单的 TextView
;
(2)然后定义横向RV 的 Item 对应的 JavaBean,这里为了节省代码,直接使用现成的 String
对象;
(3)然后是定义对应的 ItemViewBinder
,名为 ItemHorListBeanBinder.java
:
public class ItemHorListBeanBinder extends ItemViewBinder<String,ItemHorListBeanBinder.ViewHolder>{
@NonNull
@Override
protected ViewHolder onCreateViewHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {
return new ViewHolder(inflater.inflate(R.layout.item_hor_list_item, parent, false));
}
@Override
protected void onBindViewHolder(@NonNull ViewHolder holder, @NonNull String item) {
holder.textView.setText(item);
}
static class ViewHolder extends RecyclerView.ViewHolder {
public TextView textView;
public ViewHolder(View itemView) {
super(itemView);
textView = (TextView) itemView;
}
}
}
(4)接着就要为竖向的 RV 中那个特殊的 Item(即对应横向 RV 的)定义布局文件,名为 item_hor_rv_layout.xml
,里面就一个独立的 RV:
.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="50dp">
.support.v7.widget.RecyclerView>
(5)然后上述的特殊的 Item 定义对应的 JavaBean,名为:HorListBean.java
:
public class HorListBean {
// 用来存放横向 RV 的 Item 数据
private List<String> data;
public HorListBean(List<String> data) {
this.data = data;
}
public List<String> getData() {
return data;
}
public void setData(List<String> data) {
this.data = data;
}
}
这里只是简单的实现,如原文中的,还可以用一个成员变量记录横向 RV 的滑动到某一处的位置,用于在竖向的 RV 的 Item 因上下滑动刷新之后能使横向的 RV 能够恢复到原来的滑动的位置,使逻辑更加的完善。
(6)然后定义对应的 ItemViewBinder
,名为 HorListBinder.java
:
public class HorListBinder extends ItemViewBinder<HorListBean, HorListBinder.ViewHolder> {
@NonNull
@Override
protected ViewHolder onCreateViewHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {
return new ViewHolder(inflater.inflate(R.layout.item_hor_rv_layout, parent, false));
}
@Override
protected void onBindViewHolder(@NonNull ViewHolder holder, @NonNull HorListBean item) {
Items items = new Items();
List list = item.getData();
for (String s : list) {
items.add(s);
}
holder.setData(items);
}
static class ViewHolder extends RecyclerView.ViewHolder {
private RecyclerView recyclerView;
private MultiTypeAdapter adapter;
public ViewHolder(View itemView) {
super(itemView);
recyclerView = (RecyclerView) itemView;
adapter = new MultiTypeAdapter();
adapter.register(String.class, new ItemHorListBeanBinder());
LinearLayoutManager manager = new LinearLayoutManager(itemView.getContext());
//设置为横向的
manager.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(manager);
recyclerView.setAdapter(adapter);
}
public void setData(Items items) {
adapter.setItems(items);
adapter.notifyDataSetChanged();
}
}
}
在 ViewHolder
中完成对横向 RV 的相关初始化。
(7)最后就只需要为竖向的 RV 对应的 MultiTypeAdapter
实例进行类型注册 :
adapter.register(HorListBean.class, new HorListBinder());
然后为其对应的 Items 添加 HorListBean
实例即可:
items.add(new HorListBean(list));
效果图:
根据以上总结,要分别定义两组 JavaBean 与 ItemViewBinder以及对应的 Item Layout。
1、在使用 MultiType 的时候,不可避免的要根据需求实现对应的 JavaBean 与 ItemViewBinder,以及对应的 Item Lauout,有时候就让人觉得麻烦,因为每一种 Item 都要实现对应的 JavaBean 与 ItemViewBinder,在项目层次上也会多了需要的 Java 类,为了缓解这种情况, Multitype 有实现 一个类型对应多个 ItemViewBinder
,来减少 JavaBean 类型的书写。
而在有些情况下,也可以为 JavaBean 对应一个基类,然后在继承该基类实现具体的逻辑,而在使用 adapter.register()
进行类型注册的时候,就可以实现多个子类对应一个 ItemViewBinder,然后在 onBindViewHolder
中根据传入的实例的具体子类型再做判断,修改布局的样式等。就比如下面的效果:
先定义 JavaBean 基类:
public class TextViewBean {
protected String text;
public TextViewBean(String text) {
this.text = text;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
然后实现具体的子类 Post :
public class Post extends TextViewBean {
public List comments;
public Post(String text) {
super(text);
}
}
和 Comment:
public class Comment extends TextViewBean{
public Comment(String text) {
super(text);
}
}
然后是公共的 ItemViewBinder:
public class TextViewBinder extends ItemViewBinder<TextViewBean,TextViewBinder.ViewHoler> {
@NonNull
@Override
protected ViewHoler onCreateViewHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {
// 对应的布局文件里面就是一个单独的 TextView
View view = inflater.inflate(R.layout.item_text_layout, parent, false);
return new ViewHoler(view);
}
@Override
protected void onBindViewHolder(@NonNull ViewHoler holder, @NonNull TextViewBean item) {
holder.textView.setText(item.getText());
Resources resources= holder.textView.getContext().getResources();
// 根据 item 的具体类型动态的变换 TextView 样式
if (item instanceof Post) {
holder.textView.setGravity(Gravity.LEFT);
holder.textView.setBackgroundColor(resources.getColor(R.color.colorAccent));
} else {
holder.textView.setGravity(Gravity.RIGHT);
holder.textView.setBackgroundColor(resources.getColor(R.color.colorPrimary));
}
holder.textView.setTextColor(resources.getColor(R.color.white));
holder.textView.setTextSize(20);
}
static class ViewHoler extends RecyclerView.ViewHolder{
@NonNull
final TextView textView;
public ViewHoler(View itemView) {
super(itemView);
textView= (TextView) itemView;
}
}
}
然后分别注册就行了:
adapter.register(Post.class, new TextViewBinder());
adapter.register(Comment.class, new TextViewBinder());
2、还有一个点需要注意,就是复杂样式的排版布局顺序,依赖于 Items 中各种类型元素的添加顺序。