BRVAH多布局
一.简介
利用BRVAH制作多布局列表
官方的使用指南
二.使用
1.简单使用
1)实体类
在创建实体类时必须实现MultiItemEntity,在设置数据的时候,需要给每一个数据设置item Type
package com.example.day3_27.entity;
import com.chad.library.adapter.base.entity.MultiItemEntity;
import java.util.List;
public class DishEntity {
private int ret;
private List<DataBean> data;
public int getRet() {
return ret;
}
public void setRet(int ret) {
this.ret = ret;
}
public List<DataBean> getData() {
return data;
}
public void setData(List<DataBean> data) {
this.data = data;
}
public static class DataBean implements MultiItemEntity {
/**
* id : 8289
* title : 油焖大虾
* pic : http://www.qubaobei.com/ios/cf/uploadfile/132/9/8289.jpg
* collect_num : 1670
* food_str : 大虾 葱 生姜 植物油 料酒
* num : 1670
*/
private String id;
private String title;
private String pic;
private String collect_num;
private String food_str;
private int num;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getPic() {
return pic;
}
public void setPic(String pic) {
this.pic = pic;
}
public String getCollect_num() {
return collect_num;
}
public void setCollect_num(String collect_num) {
this.collect_num = collect_num;
}
public String getFood_str() {
return food_str;
}
public void setFood_str(String food_str) {
this.food_str = food_str;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public static final int TYPE_LEFT = 0;
public static final int TYPE_RIGHT = 1;
@Override
public int getItemType() {
if (Integer.parseInt(id) % 2 == 1) {
return TYPE_RIGHT;
} else {
return TYPE_LEFT;
}
}
}
}
2)适配器
适配器实现BaseMultiItemQuickAdapter
两个泛型: 实体类,BaseViewHolder
在适配器构造里面addItemType绑定type和layout的关系
public class MyAdapter extends BaseMultiItemQuickAdapter<DishEntity.DataBean, BaseViewHolder> {
public MyAdapter(List<DishEntity.DataBean> data) {
super(data);
addItemType(DishEntity.DataBean.TYPE_LEFT, R.layout.item_left);
addItemType(DishEntity.DataBean.TYPE_RIGHT, R.layout.item_right);
}
@Override
protected void convert(BaseViewHolder helper, DishEntity.DataBean item) {
switch (helper.getItemViewType()) {
case DishEntity.DataBean.TYPE_LEFT:
helper.setText(R.id.te_left, item.getTitle());
Glide.with(mContext)
.load(item.getPic())
.transform(new CircleCrop())
.into((ImageView) helper.getView(R.id.img_left));
break;
case DishEntity.DataBean.TYPE_RIGHT:
helper.setText(R.id.te_right, item.getTitle());
Glide.with(mContext)
.load(item.getPic())
.transform(new RoundedCorners(20))
.into((ImageView) helper.getView(R.id.img_right));
break;
}
}
}
4)Activity
Activity创建适配器设置到RecyclerView
public class MainActivity extends AppCompatActivity {
private RecyclerView rv;
private String url = "http://www.qubaobei.com/ios/cf/dish_list.php?stage_id=1&limit=20&page=1";
private MyAdapter myAdapter;
private List<DishEntity.DataBean> datas = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
initDatas();
}
private void initDatas() {
OkGo.<String>get(url)
.execute(new StringCallback() {
@Override
public void onSuccess(Response<String> response) {
DishEntity dishEntity = new Gson().fromJson(response.body(), DishEntity.class);
datas.addAll(dishEntity.getData());
myAdapter.notifyDataSetChanged();
}
});
}
private void initViews() {
rv = (RecyclerView) findViewById(R.id.rv);
myAdapter = new MyAdapter(datas);
//设置展示方式
rv.setLayoutManager(new LinearLayoutManager(this));
//添加分割线
rv.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
rv.setAdapter(myAdapter);
}
}
5)布局文件
主布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.recyclerview.widget.RecyclerView>
</LinearLayout>
两个子布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:src="@mipmap/ic_launcher"
android:id="@+id/img_left"
android:layout_width="100dp"
android:layout_height="100dp" />
<TextView
android:id="@+id/te_left"
android:text="123456"
android:layout_toRightOf="@id/img_left"
android:layout_centerVertical="true"
android:layout_marginLeft="20dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:src="@mipmap/ic_launcher"
android:id="@+id/img_right"
android:layout_alignParentRight="true"
android:layout_width="100dp"
android:layout_height="100dp" />
<TextView
android:id="@+id/te_right"
android:text="123456"
android:layout_toLeftOf="@id/img_right"
android:layout_centerVertical="true"
android:layout_marginRight="20dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
6)效果展示
2.案例一
1)思路
- 利用BRVAH制作类似于微信联系人列表
- 主列表为联系人,右侧列表为导航
- 滑动联系人列表,导航列表跟着变化
- 点击右侧列表,联系人列表变化
2)封装实体类
定义两个类型来区分,是联系人内容还是标题内容
public class PersonEntity implements MultiItemEntity {
public static int TYPE_TITLE = 0;//标题item
public static int TYPE_PERSON = 1;//用户item
private String name;//姓名
private int type;//类型 0 1
private String title;//标题 A B C
private String image_url;//头像
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getImage_url() {
return image_url;
}
public void setImage_url(String image_url) {
this.image_url = image_url;
}
public PersonEntity(String name, int type, String title, String image_url) {
this.name = name;
this.type = type;
this.title = title;
this.image_url = image_url;
}
@Override
public int getItemType() {
return type;
}
}
3)联系人列表的适配器
public class PerSonAdapter extends BaseMultiItemQuickAdapter<PersonEntity, BaseViewHolder> {
public PerSonAdapter(List<PersonEntity> data) {
super(data);
addItemType(PersonEntity.TYPE_TITLE, R.layout.item_main_title);
addItemType(PersonEntity.TYPE_PERSON, R.layout.item_main_person);
}
@Override
protected void convert(BaseViewHolder helper, PersonEntity item) {
if(helper.getItemViewType() == PersonEntity.TYPE_PERSON){//用户
helper.setText(R.id.tv_main_name,item.getName()+"");
Glide.with(mContext).load(item.getImage_url())
.transform(new CenterCrop(),new RoundedCorners(10))
.into((ImageView) helper.getView(R.id.iv_main));
}else if(helper.getItemViewType() == PersonEntity.TYPE_TITLE){//标题
helper.setText(R.id.tv_main_tile,item.getTitle());
}
}
}
4)右侧导航列表的适配器
public class RightTitleAdapter extends BaseQuickAdapter<String, BaseViewHolder> {
public int select_position = 0;//默认选中的下标
public RightTitleAdapter(int layoutResId, @Nullable List<String> data) {
super(layoutResId, data);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
protected void convert(BaseViewHolder helper, String item) {
helper.setText(R.id.tv_right,item+"");
TextView textView = helper.getView(R.id.tv_right);
if(helper.getLayoutPosition() == select_position){//选中
textView.setTextColor(Color.WHITE);
textView.setBackground(mContext.getDrawable(R.drawable.shape));
}else{
textView.setTextColor(Color.BLACK);
textView.setBackground(null);
}
}
}
5)Activity
其中的两个方法
-
onLeftScroll是用来在联系人列表滑动时,改变导航列表其中的背景颜色LinearLayoutManager提供了findFirstCompletelyVisibleItemPosition方法用来获取当前列表第一个可见item的位置,然后根据该位置去改变右侧列表
-
onRightClick是用来在点击头侧导航列表时,将联系人的第一个item改变,
LinearLayoutManager的scrollToPositionWithOffset方法,第一个参数为要滑动到的position,第二个参数为偏移量
public class MainActivity extends AppCompatActivity {
private RecyclerView rv_main;
private PerSonAdapter perSonAdapter;
private ArrayList<PersonEntity> list = new ArrayList<>();
private String url = "https://c-ssl.duitang.com/uploads/item/201906/01/20190601023303_dkeof.thumb.1000_0.jpg";
private LinearLayoutManager layoutManager;
private RecyclerView rv_right;
private ArrayList<String> list_right = new ArrayList<>();
private RightTitleAdapter rightTitleAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
}
private void initData() {
for (int i = 'A'; i <= 'Z'; i++) {
String title = (char) i + "";
list.add(new PersonEntity("", PersonEntity.TYPE_TITLE, title, ""));
list.add(new PersonEntity(title + "1", PersonEntity.TYPE_PERSON, title, url));
list.add(new PersonEntity(title + "2", PersonEntity.TYPE_PERSON, title, url));
list.add(new PersonEntity(title + "3", PersonEntity.TYPE_PERSON, title, url));
list_right.add(title);
}
perSonAdapter.notifyDataSetChanged();
rightTitleAdapter.notifyDataSetChanged();
}
private void initView() {
rv_main = findViewById(R.id.rv_main);
perSonAdapter = new PerSonAdapter(list);
rv_main.setAdapter(perSonAdapter);
layoutManager = new LinearLayoutManager(this);
rv_main.setLayoutManager(layoutManager);
rv_main.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
rv_right = findViewById(R.id.rv_right);
rightTitleAdapter = new RightTitleAdapter(R.layout.item_right, list_right);
rv_right.setAdapter(rightTitleAdapter);
rv_right.setLayoutManager(new LinearLayoutManager(this));
rightTitleAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
rightTitleAdapter.select_position = position;
rightTitleAdapter.notifyDataSetChanged();
}
});
onLeftScroll();
onRightClick();
}
private void onRightClick() {
rightTitleAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
//更改右列表的背景
rightTitleAdapter.select_position = position;
rightTitleAdapter.notifyDataSetChanged();
String title = list_right.get(position);
for (int i = 0; i < list.size(); i++) {
PersonEntity personEntity = list.get(i);
//title相同 同时type是title
if (title.equals(personEntity.getTitle()) && personEntity.getType() == PersonEntity.TYPE_TITLE) {
layoutManager.scrollToPositionWithOffset(i, 0);
}
}
}
});
}
private void onLeftScroll() {
rv_main.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int position = layoutManager.findFirstCompletelyVisibleItemPosition();
PersonEntity personEntity = list.get(position);
for (int i = 0; i < list_right.size(); i++) {
if (list_right.get(i).equals(personEntity.getTitle())) {
//改变右列表的背景
rightTitleAdapter.select_position = i;
rightTitleAdapter.notifyDataSetChanged();
}
}
}
});
}
}
6)布局文件
主布局
注意联系人用的第一个RecyclerView,使用多布局方式加载联系人和联系人的标题
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_main"
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.recyclerview.widget.RecyclerView>
<androidx.recyclerview.widget.RecyclerView
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:id="@+id/rv_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</androidx.recyclerview.widget.RecyclerView>
</RelativeLayout>
联系人的布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="100dp">
<ImageView
android:layout_gravity="center_vertical"
android:padding="10dp"
android:layout_marginLeft="10dp"
android:id="@+id/iv_main"
android:src="@drawable/ic_launcher_background"
android:layout_width="80dp"
android:layout_height="80dp">
</ImageView>
<TextView
android:layout_marginLeft="10dp"
android:gravity="center_vertical"
android:text="hahah"
android:textStyle="bold"
android:id="@+id/tv_main_name"
android:textSize="20sp"
android:layout_width="match_parent"
android:layout_height="match_parent">
</TextView>
</LinearLayout>
联系人的标题布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:background="@color/colorGray"
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="50dp">
<TextView
android:textSize="15sp"
android:gravity="center_vertical"
android:text="sddd"
android:layout_marginLeft="10dp"
android:id="@+id/tv_main_tile"
android:layout_width="wrap_content"
android:layout_height="match_parent">
</TextView>
</LinearLayout>
右侧导航布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:textSize="10sp"
android:gravity="center"
android:text="A"
android:id="@+id/tv_right"
android:layout_width="15dp"
android:layout_height="15dp">
</TextView>
</LinearLayout>
7)效果展示
3.案例二
利用BRVAH做类似于新闻展示的列表
其中一种布局为RecylerView的横向列表
只需要给linearLayoutManager.setOrientation(RecyclerView.HORIZONTAL);
即可实现
1)实体类
因为是加载本地图片,所以只添加type分辨哪种布局
public class NewsEntity implements MultiItemEntity {
public static final int TYPE_ONE = 0;
public static final int TYPE_TWO = 1;
private int type;
public NewsEntity(int type) {
this.type = type;
}
@Override
public int getItemType() {
return type;
}
}
2)总的适配器
这里的第二种布局,用的横向列表加载的,所以嵌套了一个RecyclerView
public class Main_Adapter extends BaseMultiItemQuickAdapter<NewsEntity, BaseViewHolder> {
public Main_Adapter(List<NewsEntity> data) {
super(data);
addItemType(NewsEntity.TYPE_ONE, R.layout.item_one);
addItemType(NewsEntity.TYPE_TWO, R.layout.item_two);
}
@Override
protected void convert(BaseViewHolder helper, NewsEntity item) {
switch (helper.getItemViewType()) {
case NewsEntity.TYPE_ONE:
Glide.with(mContext)
.load(R.drawable.bg_motherland)
.into((ImageView) helper.getView(R.id.iv));
break;
case NewsEntity.TYPE_TWO:
RecyclerView rv = helper.getView(R.id.rv_two);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(mContext);
linearLayoutManager.setOrientation(RecyclerView.HORIZONTAL);
rv.setLayoutManager(linearLayoutManager);
List<Integer> datas = new ArrayList<>();
datas.add(R.drawable.bg_motherland);
datas.add(R.drawable.bg_motherland);
datas.add(R.drawable.bg_motherland);
datas.add(R.drawable.bg_motherland);
datas.add(R.drawable.bg_motherland);
datas.add(R.drawable.bg_motherland);
ImgAdapter imgAdapter = new ImgAdapter(R.layout.two_img, datas);
rv.setAdapter(imgAdapter);
break;
}
}
}
3)横向列表的适配器
public class ImgAdapter extends BaseQuickAdapter<Integer, BaseViewHolder> {
public ImgAdapter(int layoutResId, @Nullable List<Integer> data) {
super(layoutResId, data);
}
@Override
protected void convert(BaseViewHolder helper, Integer item) {
Glide.with(mContext)
.load(item)
.transform(new CenterCrop())
.into((ImageView) helper.getView(R.id.two_img_show));
}
}
4)Activity
public class MainActivity extends AppCompatActivity {
private RecyclerView rv;
private Main_Adapter main_adapter;
private List<NewsEntity> datas = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
initDatas();
}
private void initDatas() {
datas.add(new NewsEntity(NewsEntity.TYPE_TWO));
datas.add(new NewsEntity(NewsEntity.TYPE_ONE));
datas.add(new NewsEntity(NewsEntity.TYPE_ONE));
datas.add(new NewsEntity(NewsEntity.TYPE_TWO));
datas.add(new NewsEntity(NewsEntity.TYPE_ONE));
datas.add(new NewsEntity(NewsEntity.TYPE_ONE));
datas.add(new NewsEntity(NewsEntity.TYPE_TWO));
datas.add(new NewsEntity(NewsEntity.TYPE_ONE));
main_adapter.notifyDataSetChanged();
}
private void initViews() {
rv = (RecyclerView) findViewById(R.id.rv);
main_adapter = new Main_Adapter(datas);
rv.setAdapter(main_adapter);
rv.setLayoutManager(new LinearLayoutManager(this));
}
}
5)布局文件
主布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.recyclerview.widget.RecyclerView>
</LinearLayout>
第一种布局的布局文件
第一种布局几乎就一个图片
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:orientation="vertical">
<LinearLayout
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="30dp">
<TextView
android:background="@drawable/shape_but"
android:text="专题"
android:padding="5dp"
android:textColor="#FFF"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:textColor="#000"
android:layout_marginLeft="10dp"
android:textSize="20sp"
android:text="一个有希望的民族"
android:layout_width="match_parent"
android:layout_height="wrap_content"></TextView>
</LinearLayout>
<ImageView
android:scaleType="centerCrop"
android:padding="10dp"
android:id="@+id/iv"
android:src="@drawable/bg_motherland"
android:layout_width="match_parent"
android:layout_height="150dp"></ImageView>
<LinearLayout
android:layout_marginBottom="10dp"
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="30dp">
<TextView
android:layout_marginLeft="10dp"
android:textColor="#206DD1"
android:text="置顶"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</TextView>
<TextView
android:text="澎湃新闻"
android:textColor="#999"
android:layout_marginLeft="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</TextView>
<TextView
android:text="13小时"
android:textColor="#999"
android:layout_marginLeft="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</TextView>
<TextView
android:text="200万阅"
android:textColor="#999"
android:layout_marginLeft="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</TextView>
</LinearLayout>
</LinearLayout>
第二种布局,横向列表展示图片,利用RecyclerView
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_two"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</androidx.recyclerview.widget.RecyclerView>
<TextView
android:textSize="20sp"
android:textColor="#5C4F4B"
android:text="查看更多事件"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="40dp">
</TextView>
</LinearLayout>
第二种布局所用的item布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/two_img_show"
android:layout_width="match_parent"
android:layout_height="150dp" />
</LinearLayout>
6)效果展示
要开心加油