本文基于baseRecyclerView依赖库.
先来看效果图:
首先,添加依赖:
compile 'com.android.support:design:26.0.0-alpha1'
compile 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.25'
首先,先写一个简单的布局:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
再写三个item的布局,最外层到最内层分别为红绿蓝.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ff0000"
android:orientation="vertical">
<TextView
android:id="@+id/tv_one"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
我们需要分别为每个item写javabean.
OneBean.java
public class OneBean extends AbstractExpandableItem<TwoBean> implements MultiItemEntity {
private String textOne;
public String getTextOne() {
return textOne;
}
public void setTextOne(String textOne) {
this.textOne = textOne;
}
/**
* javabean中需要绑定adapter中addItemType的类型(这是为了在adapter中的convert中进行区分)
* @return
*/
@Override
public int getItemType() {
return MainAdapter.TYPE_LEVEL_0;
}
/**
* 从第几个item开始里边有嵌套,默认是0,从第一个开始
* @return
*/
@Override
public int getLevel() {
return 0;
}
最外层的javabean,由于里边嵌套着第二层的javabean,所以继承的AbstractExpandableItem<TwoBean>
TwoBean.java
public class TwoBean extends AbstractExpandableItem<ThreeBean> implements MultiItemEntity {
private String textTwo;
public String getTextTwo() {
return textTwo;
}
public void setTextTwo(String textTwo) {
this.textTwo = textTwo;
}
@Override
public int getItemType() {
return MainAdapter.TYPE_LEVEL_1;
}
@Override
public int getLevel() {
return 0;
}
}
ThreeBean.java
public class ThreeBean implements MultiItemEntity {
private String textThree;
public String getTextThree() {
return textThree;
}
public void setTextThree(String textThree) {
this.textThree = textThree;
}
@Override
public int getItemType() {
return MainAdapter.TYPE_LEVEL_2;
}
}
由于最内层的里边不会嵌套了,就不需要继承AbstractExpandableItem
了.
下面,来看MainAdapter的代码:
public class MainAdapter extends BaseMultiItemQuickAdapter<MultiItemEntity, BaseViewHolder> {
//继承BaseMultiItemQuickAdapter<MultiItemEntity, BaseViewHolder> 是固定写法,因为javabean中都实现了MultiItemEntity
public static final int TYPE_LEVEL_0 = 0;
public static final int TYPE_LEVEL_1 = 1;
public static final int TYPE_LEVEL_2 = 2;
public MainAdapter(List<MultiItemEntity> data) {
super(data);
//初始化adapter的时候把所有嵌套的布局都添加上
addItemType(TYPE_LEVEL_0,R.layout.item_one);//第一层布局(最外层)
addItemType(TYPE_LEVEL_1,R.layout.item_two);//第二层布局
addItemType(TYPE_LEVEL_2,R.layout.item_three);//第三层布局
}
@Override
protected void convert(final BaseViewHolder helper, MultiItemEntity item) {
switch (helper.getItemViewType()) {
case TYPE_LEVEL_0 : //第一层布局
final OneBean oneBean = (OneBean) item;
//设置最外层 数据+位置(位置不能用getLayoutPosition方法,因为getLayoutPosition方法得到的位置是包含了整个的item位置从外层到里层依次数,而我们要的位置是这一层的位置)
helper.setText(R.id.tv_one,oneBean.getTextOne() + helper.getAdapterPosition());
//设置点击外层item展开或关闭里边的item(固定写法)
helper.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//得到点击位置
int position = helper.getAdapterPosition();
if(oneBean.isExpanded()) {
//item是展开的
//关闭对应的item
collapse(position);
}else {
//item是关闭的,展开item
expand(position);
}
}
});
break;
case TYPE_LEVEL_1: //第二层布局
final TwoBean twoBean = (TwoBean) item;
//设置第二层外层 数据+位置
helper.setText(R.id.tv_two,twoBean.getTextTwo() + helper.getAdapterPosition());
//设置点击第二层item展开或关闭第二层里边的item
helper.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//得到点击位置
int position = helper.getAdapterPosition();
if(twoBean.isExpanded()) {
//item是展开的
//关闭对应的item
collapse(position,false);
}else {
//item是关闭的,展开item
expand(position,false);
}
}
});
break;
case TYPE_LEVEL_2: //第三层布局
ThreeBean threeBean = (ThreeBean) item;
//设置最内层 数据+位置
helper.setText(R.id.tv_three,threeBean.getTextThree() + helper.getAdapterPosition());
//设置里层的点击事件
helper.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//得到点击位置
int position = helper.getAdapterPosition();
Toast.makeText(mContext, ("点击了最内层的item"+position), Toast.LENGTH_SHORT).show();
}
});
break;
}
}
}
下面,来看activity中的代码:
public class MainActivity extends Activity {
private RecyclerView rv;
private List<MultiItemEntity> mData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
rv = (RecyclerView) findViewById(R.id.rv);
//初始化数据
initData();
final MainAdapter adapter = new MainAdapter(mData);
//设置整体的layoutmanager
final GridLayoutManager manager = new GridLayoutManager(this, 3);
//如果内外层的layoutmanager不一样呢? 需要设置setSpanSizeLookup
manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
//如果等于最内层,分别设置为1,就是每行3个;如果不是最内层,就设置每行的总个数,也就是一个item占满一行
return adapter.getItemViewType(position) == MainAdapter.TYPE_LEVEL_2 ? 1 : manager.getSpanCount();
}
});
rv.setAdapter(adapter);
//设置manager必须放在setAdapter之后,否则setSpanSizeLookup方法不生效
rv.setLayoutManager(manager);
//设置三级嵌套全部展开
adapter.expandAll();
}
private void initData() {
mData = new ArrayList<>();
int oneCount = 3;
int twoCount = 2;
int threeCount = 6;
for (int i = 0; i < oneCount; i++) {
//最外层数据
OneBean oneBean = new OneBean();
oneBean.setTextOne("我是最外层数据");
for (int i1 = 0; i1 < twoCount; i1++) {
//第二层数据
TwoBean twoBean = new TwoBean();
twoBean.setTextTwo("我是嵌套在第二层的");
for (int i2 = 0; i2 < threeCount; i2++) {
//最内层数据
ThreeBean threeBean = new ThreeBean();
threeBean.setTextThree("我是嵌套在最里层的");
//最内层数据添加到第二层中
twoBean.addSubItem(threeBean);
}
//第二层数据添加到第一层中
oneBean.addSubItem(twoBean);
}
//拿到所有数据
mData.add(oneBean);
}
}
}