Android RecyclerView 二级列表实现
前段时间项目提了个新需求:我的红包需要做成二级列表的形式,实现的效果如下图所示:
支持的功能:
1.可自定义item的样式
2.自定义折叠效果
3.自定义展开方式
下面我说一下我在demo中的使用方式
1.demo中的数据来源于这样格式的json,所以你可以让后端给你返回包含这样格式的json
2.MainActivity的布局activity_main.xml如下:
<?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:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="view.lyd.com.sectionrecyclerviewdemo.MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
3.适配器HotelEntityAdapter:
package adapter;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import java.util.ArrayList;
import entity.HotelEntity;
import utils.HotelUtils;
import view.lyd.com.sectionrecyclerviewdemo.R;
/**
* Created by yushuangping on 2018/8/23.
*/
public class HotelEntityAdapter extends SectionedRecyclerViewAdapter<HeaderHolder, DescHolder, RecyclerView.ViewHolder> {
public ArrayList<HotelEntity.TagsEntity> allTagList;
private Context mContext;
private LayoutInflater mInflater;
private SparseBooleanArray mBooleanMap;//记录下哪个section是被打开的
public HotelEntityAdapter(Context context) {
mContext = context;
mInflater = LayoutInflater.from(context);
mBooleanMap = new SparseBooleanArray();
}
public void setData(ArrayList<HotelEntity.TagsEntity> allTagList) {
this.allTagList = allTagList;
mBooleanMap.put(0, true);
notifyDataSetChanged();
}
/**
* 一共有多少个section需要展示, 返回值是我们最外称list的大小,在我们的示例图中,
* 对应的为热门品牌—商业区—热门景点 等,对应的数据是我们的allTagList
*
* @Override
*/
protected int getSectionCount() {
return HotelUtils.isEmpty(allTagList) ? 0 : allTagList.size();
}
/**
* 来展示content内容区域,返回值是我们需要展示多少内容,在本例中,我们超过8条数据只展示8条,
* 点击展开后就会展示全部数据,逻辑就在这里控制。 对应数据结构为tagInfoList
*
* @param section
* @return
*/
@Override
protected int getItemCountForSection(int section) {
int count = allTagList.get(section).tagInfoList.size();
if (count >= 1 && !mBooleanMap.get(section)) {
count = 0;
}
if (section==0&&mBooleanMap.get(section)){
count = allTagList.get(section).tagInfoList.size();
}
return HotelUtils.isEmpty(allTagList.get(section).tagInfoList) ? 0 : count;
}
//是否有footer布局
/**
* 判断是否需要底部footer布局,在该例中,我们并不需要显示footer,所以默认返回false就可以,
* 如果你对应的section需要展示footer布局,那么就在对应的section返回true就行了
*
* @param section
* @return
*/
@Override
protected boolean hasFooterInSection(int section) {
return false;
}
@Override
protected HeaderHolder onCreateSectionHeaderViewHolder(ViewGroup parent, int viewType) {
return new HeaderHolder(mInflater.inflate(R.layout.hotel_title_item, parent, false));
}
@Override
protected RecyclerView.ViewHolder onCreateSectionFooterViewHolder(ViewGroup parent, int viewType) {
return null;
}
@Override
protected DescHolder onCreateItemViewHolder(ViewGroup parent, int viewType) {
return new DescHolder(mInflater.inflate(R.layout.hotel_desc_item, parent, false));
}
@Override
protected void onBindSectionHeaderViewHolder(final HeaderHolder holder, final int section) {
holder.openView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean isOpen = mBooleanMap.get(section);
// String text = isOpen ? "展开" : "关闭";
mBooleanMap.put(section, !isOpen);
// holder.openView.setText(text);
notifyDataSetChanged();
}
});
holder.titleView.setText(allTagList.get(section).tagsName);
// holder.openView.setText(mBooleanMap.get(section) ? "关闭" : "展开");//true显示关闭字段,false显示展开字段
holder.openView.setBackgroundResource(mBooleanMap.get(section) ? R.mipmap.arrow_up : R.mipmap.arrow_down);
}
@Override
protected void onBindSectionFooterViewHolder(RecyclerView.ViewHolder holder, int section) {
}
/**
* 这里有一个section和position ,有些人可能会弄混
* section是区域,也就是我们最外层的index,position是每个section对应的内容数据的position
*
* @param holder
* @param section
* @param position
*/
@Override
protected void onBindItemViewHolder(DescHolder holder, final int section, final int position) {
holder.descView.setText(allTagList.get(section).tagInfoList.get(position).tagName);
Log.e("=====AAA===", "section=" + section + ",position=" + position);
holder.descView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
onItemClickListener.onItemClick(section, position);
}
});
}
private OnItemClickListener onItemClickListener;
public void setOnItemClick(OnItemClickListener listener) {
this.onItemClickListener = listener;
}
public interface OnItemClickListener {
void onItemClick(int section, int position);
}
}
4.在MainActivity中进行调用:
package view.lyd.com.sectionrecyclerviewdemo;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.widget.Toast;
import adapter.HotelEntityAdapter;
import adapter.SectionedSpanSizeLookup;
import entity.HotelEntity;
import utils.JsonUtils;
/**
* Created by yushuangping on 2018/8/23.
*/
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private HotelEntityAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
mAdapter = new HotelEntityAdapter(this);
// GridLayoutManager manager = new GridLayoutManager(this,4);
LinearLayoutManager layoutManager=new LinearLayoutManager(this);
//设置header
// manager.setSpanSizeLookup(new SectionedSpanSizeLookup(mAdapter,manager));
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setAdapter(mAdapter);
HotelEntity entity = JsonUtils.analysisJsonFile(this,"json");
mAdapter.setData(entity.allTagsList);
mAdapter.setOnItemClick(new HotelEntityAdapter.OnItemClickListener() {
@Override
public void onItemClick(int section, int position) {
Toast.makeText(MainActivity.this,section+"=="+position,Toast.LENGTH_SHORT).show();
}
});
}
}
5.最后demo运行在手机上的效果图如下:
未展开时的效果:
展开时的效果:
如果大家想看具体的实现方式可以下载源码