直接进入主题,要实现的效果如下图:
使用的是recyclerview的分组,getviewtype()方法返回不同布局。
[外链图片转存中…(img-dG1kQsW6-1569828948498)]
listview实现就是listview嵌套gridview,把每个分组当成一个listview的一个item,想象就很麻烦,接下来用recycler来实现这个效果。
首先recyclerview的基本用法要会,这里我就不想说recyclerview的基本用法了不太了解的可以看看鸿洋的博客点这里,讲的挺详细的,看完基本使用应该没问题了。
实现思路:
其实以前也做过类似的效果就是用的listview加gridview,所以我才说很麻烦,listview中adapter中有个方法是getItemViewType()根据item返回不同的layout,在getview()中加载不同布局,再来看看那下面的图片,
一:
首先就是数据list集合。1-8这些所有的数据是放在一个list< Entity >中的,Entity就是服务器返回的数据,只不过在其中加了一个key用于标识当前item是分组还是组员,再根据这个key在getItemViewType()返回不同的type,一般服务器返回的格式如下
{
"resultMsg":{
"groupList":[
{
"childList":[
{
"childName":"组员1",
"openTime":"2017-04-20 11:40:18"
},
{
"childName":"组员2",
"openTime":"2017-04-20 11:40:18"
},
{
"childName":"组员3",
"openTime":"2017-04-20 11:40:18"
}
],
"groupName":"分组1"
},
{
"childList":[
{
"childName":"组员1",
"openTime":"2017-07-06 10:05:16"
},
{
"childName":"组员2",
"openTime":"2017-07-06 10:05:16"
}
],
"groupName":"分组2"
}
]
}
}
二
将上述json数据添加到一个list中,看看上面的数据,一层套着一层,grouplist中套着childlist,一般分组的数据都是这样的json格式。
这里就需要用到map,以key-vale的形式将json数据保存下来,map最好用LinkedHashMap;
LinkedHashMap是有序的存储的你存和取得顺序是一致的,key是groupName; value是组员的list集合,代码如下:
private LinkedHashMap> groupMap =
new LinkedHashMap>();
三
数据保存下来后就调用adapter的setList()方法刷新数据,在setList()方法方法中遍历map将所有数据添加到一个list中代码如下:
/**
* @param map
*/
public void setList(LinkedHashMap> map) {
Iterator iterator = map.keySet().iterator();
while (iterator.hasNext()) {
String key = iterator.next().toString();
//遍历数组
if (map.get(key).size() > 0) {
//这里是将group当成一个child一起加到mList中
//也就是mList中包含了group和child,只不过group
//所在的positon有个标识当前position是否为分组
mList.add(new ChildListBean(key, true));
}
mList.addAll(map.get(key));
}
notifyDataSetChanged();
}
再来看看实体类代码,这个有必要贴出来,主要就是ChildListBean 的两个构造方法,如果group还有其他的信息都可以这样加进来,需要什么setXXX什么显示的时候在getXXX,这样就把group信息和child信息添加到一个list中了。
public class GroupChildBean {
private ResultMsgBean resultMsg;
public ResultMsgBean getResultMsg() {
return resultMsg;
}
public void setResultMsg(ResultMsgBean resultMsg) {
this.resultMsg = resultMsg;
}
public static class ResultMsgBean {
private List groupList;
public List getGroupList() {
return groupList;
}
public void setGroupList(List groupList) {
this.groupList = groupList;
}
public static class GroupListBean {
private String groupName;
private List childList;
public String getGroupName() {
return groupName;
}
public void setGroupName(String groupName) {
this.groupName = groupName;
}
public List getChildList() {
return childList;
}
public void setChildList(List childList) {
this.childList = childList;
}
public static class ChildListBean {
private String childName;
private String openTime;
private boolean isGroup;
/**
* 添加child
*
* @param childName
*/
public ChildListBean(String childName) {
this.childName = childName;
}
/**
* 把group当成child
*
* @param childName
* @param isGroup
*/
public ChildListBean(String childName, boolean isGroup) {
this.childName = childName;
this.isGroup = isGroup;
}
public boolean isGroup() {
return isGroup;
}
public void setGroup(boolean group) {
isGroup = group;
}
public String getChildName() {
return childName;
}
public void setChildName(String childName) {
this.childName = childName;
}
public String getOpenTime() {
return openTime;
}
public void setOpenTime(String openTime) {
this.openTime = openTime;
}
}
}
}
}
四
有了list集合那就很简单了,接下来就是recyclerview的基本用法了.
就是需要在getViewType中判断是否为分组返回不同的type
@Override
public int getItemViewType(int position) {
if (mList.get(position).isGroup()) {
return GROUP_ITEM_TYPE;
} else {
return CHILD_ITEM_TYPE;
}
}
在onBindViewHolder返回不同的viewHolder
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
final ChildListBean bean = mList.get(position);
int type = holder.getItemViewType();
if (type == GROUP_ITEM_TYPE) {
GroupViewHolder holder1 = (GroupViewHolder) holder;
holder1.textView.setText(bean.getChildName());
holder1.cardView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(mContext, bean.getChildName(), Toast.LENGTH_SHORT).show();
}
});
} else {
ChildViewHolder holder1 = (ChildViewHolder) holder;
holder1.textView.setText(bean.getChildName());
holder1.cardView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(mContext, bean.getChildName(), Toast.LENGTH_SHORT).show();
}
});
}
}
/**
* 分组
*/
class GroupViewHolder extends RecyclerView.ViewHolder {
TextView textView;
CardView cardView;
public GroupViewHolder(View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.header);
cardView = (CardView) itemView.findViewById(R.id.card_view);
}
}
/**
* 成员
*/
class ChildViewHolder extends RecyclerView.ViewHolder {
TextView textView;
CardView cardView;
public ChildViewHolder(View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.tv);
cardView = (CardView) itemView.findViewById(R.id.card_view);
}
}
在来看看Activity的代码,主要就是initView()中的代码
private void initView() {
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
initToolBar(toolbar, "分组recycler", true);
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new GridLayoutManager(this,2));
mAdapter = new GroupRecyAdapter(this);
initData();
mRecyclerView.setAdapter(mAdapter);
mAdapter.setList(groupMap);
}
和想象的不一样,因为我们之前是将group当成child一起添加到list中,所以在使用GridLayoutManager并且显示两列的时候并没有判断isGroup这个字段,所以group就跟child一样显示了,这样我们就需要加个判定了,当是group时就让他显示一列,如果是child就让他显示两列,GridLayoutManager有个方法setSpanSizeLookup()就需要我们自己去写了,代码如下,一看就懂
final GridLayoutManager manager = new GridLayoutManager(this, 2, OrientationHelper.VERTICAL, false);
manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
//当是group时就让他显示一列,如果是child就让他显示两列
return mAdapter.getItemViewType(position) == GroupRecyAdapter.GROUP_ITEM_TYPE ? manager.getSpanCount() : 1;
}
});
mRecyclerView.setLayoutManager(manager);
manager.getSpanCount()就是上面设置的默认列数
final GridLayoutManager manager = new GridLayoutManager(this, 2, OrientationHelper.VERTICAL, false);
再次运行,完美实现了recyclerview分组的效果。
总结:
recyclerview之所有强大就是因为你完全可以自定义view改如何显示,分组的方法还有很多种,这里只是其中一种。这种实现方式最主要的就两个地方,第一个就是数据处理,将group当成child添加到一个集合list中;第二呢就是 需要重写getSpanSize()方法,判断当前item是否为分组返回不同的列数。这里只有两种type,如果布局更复杂,也可以加,思路差不多。
第一次写这么长的博客,写的有点乱,凑合看吧,如有写的不好的地方希望大佬们指出。有问题可以留言或者加QQ821651400。
源码地址:https://github.com/caobin821651400/Study 在com.example.androidremark.ui2.grouprecycler目录下
这是我的一个小项目,里面包含了好多好的布局或者工具,喜欢的就start下,谢谢~
如果想直接使用可以去github搜MultiType,SLTableView都可以实现,不过封装太好了我是没看懂所以自己想办法写的。