前言
对于项目中要实现如上图所示的界面效果,可能有的人会想到使用RecycleView嵌套的方式去解决,虽然这种方式可以实现,但是嵌套带来的问题还是比较麻烦的,比如滑动冲突什么的,今天我们就介绍一种优雅的方式,只需要一个RecycleView就可以实现这样的效果,基本思路如下:
我们发现上图中的布局样式其实只有两种,我们将上图中的区域1划分为一个类型(String),区域2划分为一个类型(自定义实体类(OpenRecordBean))。将这两种类型的所有数据依次放入到一个List集合中,存放完之后,根据上面的需求,这个集合里面的结构应该是这样的:【String,OpenRecordBean,String,OpenRecordBean,OpenRecordBean,String,OpenRecordBean,OpenRecordBean,OpenRecordBean…….】,因为集合里面的元素类型并不单一,所以泛型使用Object,然后在adapter中根据集合List< Object >元素的类型,选择不同的布局去加载即可。
具体实现
该列表数据我们一般会通过一个接口从服务器端去获取,假如最终获取的json格式的数据如下:
{
"code" : 1000,
"data" : [{"dateTitle":"2018-06-14","logDOList":[{"cellId":0,"deviceName":"东大门1","deviceType":0,"fullName":"张三1","ghsUserId":0,"id":0,"openState":0,"openType":1,"roomId":0,"updateTime":"10:22","villageId":0},{"cellId":0,"deviceName":"东大门2","deviceType":0,"fullName":"张三2","ghsUserId":0,"id":0,"openState":0,"openType":2,"roomId":0,"updateTime":"10:22","villageId":0},{"cellId":0,"deviceName":"东大门3","deviceType":0,"fullName":"张三3","ghsUserId":0,"id":0,"openState":0,"openType":3,"roomId":0,"updateTime":"10:22","villageId":0}]},{"dateTitle":"2018-06-10","logDOList":[{"cellId":0,"deviceName":"南大门1","deviceType":0,"fullName":"李四1","ghsUserId":0,"id":0,"openState":0,"openType":1,"roomId":0,"updateTime":"10:22","villageId":0},{"cellId":0,"deviceName":"南大门2","deviceType":0,"fullName":"李四2","ghsUserId":0,"id":0,"openState":0,"openType":2,"roomId":0,"updateTime":"10:22","villageId":0},{"cellId":0,"deviceName":"南大门3","deviceType":0,"fullName":"李四3","ghsUserId":0,"id":0,"openState":0,"openType":3,"roomId":0,"updateTime":"10:22","villageId":0}]}]
"message" : "成功"
}
1,首先我们根据上面的json字符串我们抽象出实体类 OpenRecordBean 如下,可以借助GsonFormat生成:
public class OpenRecordBean {
private int code;
private String message;
private List<DataBean> data;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public List<DataBean> getData() {
return data;
}
public void setData(List<DataBean> data) {
this.data = data;
}
public static class DataBean {
/**
* dateTitle : 2018-06-14
* logDOList : [{"cellId":0,"deviceName":"东大门1","deviceType":0,"fullName":"张三1","ghsUserId":0,"id":0,"openState":0,"openType":1,"roomId":0,"updateTime":"10:22","villageId":0},{"cellId":0,"deviceName":"东大门2","deviceType":0,"fullName":"张三2","ghsUserId":0,"id":0,"openState":0,"openType":2,"roomId":0,"updateTime":"10:22","villageId":0},{"cellId":0,"deviceName":"东大门3","deviceType":0,"fullName":"张三3","ghsUserId":0,"id":0,"openState":0,"openType":3,"roomId":0,"updateTime":"10:22","villageId":0}]
*/
private String dateTitle;
private List<LogDOListBean> logDOList;
public String getDateTitle() {
return dateTitle;
}
public void setDateTitle(String dateTitle) {
this.dateTitle = dateTitle;
}
public List<LogDOListBean> getLogDOList() {
return logDOList;
}
public void setLogDOList(List<LogDOListBean> logDOList) {
this.logDOList = logDOList;
}
public static class LogDOListBean {
/**
* cellId : 0
* deviceName : 东大门1
* deviceType : 0
* fullName : 张三1
* ghsUserId : 0
* id : 0
* openState : 0
* openType : 1
* roomId : 0
* updateTime : 10:22
* villageId : 0
*/
private int cellId;
private String deviceName;
private int deviceType;
private String fullName;
private int ghsUserId;
private int id;
private int openState;
private int openType;
private int roomId;
private String updateTime;
private int villageId;
public int getCellId() {
return cellId;
}
public void setCellId(int cellId) {
this.cellId = cellId;
}
public String getDeviceName() {
return deviceName;
}
public void setDeviceName(String deviceName) {
this.deviceName = deviceName;
}
public int getDeviceType() {
return deviceType;
}
public void setDeviceType(int deviceType) {
this.deviceType = deviceType;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public int getGhsUserId() {
return ghsUserId;
}
public void setGhsUserId(int ghsUserId) {
this.ghsUserId = ghsUserId;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getOpenState() {
return openState;
}
public void setOpenState(int openState) {
this.openState = openState;
}
public int getOpenType() {
return openType;
}
public void setOpenType(int openType) {
this.openType = openType;
}
public int getRoomId() {
return roomId;
}
public void setRoomId(int roomId) {
this.roomId = roomId;
}
public String getUpdateTime() {
return updateTime;
}
public void setUpdateTime(String updateTime) {
this.updateTime = updateTime;
}
public int getVillageId() {
return villageId;
}
public void setVillageId(int villageId) {
this.villageId = villageId;
}
}
}
}
2,布局文件很简单就仅仅只是定义一个RecycleView控件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycleView"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
3,然后Activity中代码如下:
public class LLLActivity extends AppCompatActivity {
private RecyclerView recyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lll);
// 初始化控件
recyclerView = findViewById(recycleView);
initRecycleView();
}
private void initRecycleView() {
// 将网络请求获取到的json字符串转成的对象进行二次重组,生成集合List<Object>
List<Object> list = sortData(网络请求成功返回的OpenRecordBean对象);
LinearLayoutManager manager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(manager);
OpenRecordAddapter adapter = new OpenRecordAddapter(list);
recycleView.setAdapter(adapter);
}
// 数据拆分重新组装的方法
private List<Object> sortData(OpenRecordBean bean) {
List<OpenRecordBean.DataBean> arrays = bean.getData();
// 用来进行数据重组的新的集合arrays_obj,之所以泛型设为Object,是因为该例中的集合元素既可能为String有可能是一个bean
List<Object> arrays_obj = new ArrayList<>();
for (OpenRecordBean.DataBean array : arrays) {
List<OpenRecordBean.DataBean.LogDOListBean> logs = array.getLogDOList();
// 拿到String值添加进集合arrays_obj
arrays_obj.add(array.getDateTitle());
// 如果该标题下的集合里面有数据的话,遍历拿到添加进新集合arrays_obj
if (logs != null && logs.size() > 0) {
for (OpenRecordBean.DataBean.LogDOListBean log : logs) {
arrays_obj.add(log);
}
}
}
return arrays_obj;
}
}
4,然后主要是OpenRecordAddapter,代码如下,对应的每种情况下的布局文件也很简单,只是textview赋值而已,所以此处省略:
这里使用了BaseRecyclerViewAdapterHelper加载多类型布局两种方式的第二种方式,即判断类型的代码放在了adapter中进行了判断,对于BaseRecyclerViewAdapterHelper框架使用还不熟悉的读者请看本人之前的博客:
安卓项目实战之:开源框架BaseRecyclerViewAdapterHelper的使用
public class OpenRecordAddapter extends BaseQuickAdapter<Object, BaseViewHolder>{
public static final int ITEM_TITLE = 1;
public static final int ITEM_CONTENT = 2;
public OpenRecordAddapter(@Nullable List<Object> data) {
super(data);
// 第一步:动态判断
setMultiTypeDelegate(new MultiTypeDelegate<Object>() {
@Override
protected int getItemType(Object o) {
// 当前例子中只有两种类型
if(o instanceof String){
// 加载布局1
return ITEM_TITLE;
}else if(o instanceof OpenRecordBean.DataBean.LogDOListBean){
// 加载布局2
return ITEM_CONTENT;
}
return 0;
}
});
// 第二步:设置type和layout的对应关系
getMultiTypeDelegate().registerItemType(ITEM_TITLE,R.layout.open_record_title)
.registerItemType(ITEM_CONTENT,R.layout.open_record_content);
}
@Override
protected void convert(BaseViewHolder helper, Object item) {
// 第三步:设置不同布局下的组件数据
switch (helper.getItemViewType()) {
case ITEM_TITLE:
// 标题赋值
helper.setText(R.id.open_record_date_tv,(String)item);
break;
case ITEM_CONTENT:
helper.setText(R.id.open_record_time_tv,((OpenRecordBean.DataBean.LogDOListBean)item).getUpdateTime())
.setText(R.id.open_record_terminal_tv,((OpenRecordBean.DataBean.LogDOListBean) item).getDeviceName())
.setText(R.id.open_record_name_tv,((OpenRecordBean.DataBean.LogDOListBean) item).getFullName())
.setText(R.id.open_record_door_NO_tv,""+((OpenRecordBean.DataBean.LogDOListBean) item).getOpenType());
break;
}
}
}
经过上面四步,我们就做到了仅仅用了一个RecycleView就实现列表嵌套的效果。