饭后Android第四餐-BRVAH(最好用的数据适配器)
官方引言:Recyclerview作为Android最常用的控件之一,是否常常为“她”操碎了心
BRVAH受益群体是所有Android开发者,希望更多开发者能够一起来把这个项目做得更好帮助更多人
我的感受:学会了这个框架以后,在使用recyclerview上会大大节省时间,真的是大大节省时间奥,话不多说,干代码来
1.BRVAH简介
BRVAH是一个强大的RecyclerAdapter框架,它能节约开发者大量的开发时间,集成了大部分列表常用需求解决方案
官网地址
GitHub地址
BRVAH官方使用指南(持续更新)
推荐博主文章
1.开源框架BaseRecyclerViewAdapterHelper使用——RecyclerView万能适配器
BRVAH全称BaseRecyclerViewAdapterHelper,它是一款针对在recyclerview使用中节省开发者时间的开源框架,在以往的开发中,我们需要重写holder和adapter,而BRVAH将hodler和adapter进行了封装,且recyclerview的adapter用BRVAH来实现比起原生可以减少70%的代码量
2.使用方法
1.引入框架
maven {
url "https://jitpack.io" }
注意是在build.gradle(Project:XXXX) 的 repositories 添加:
然后在 build.gradle(Module:app) 的 dependencies 添加依赖:
compile 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.22'
官方作者提示:
更新说明:https://github.com/CymChad/BaseRecyclerViewAdapterHelper/releases
注意 版本:2.9.28 Change the method setVisible --> setGone The new method setVisible
setVisible:Set a view visibility to VISIBLE (true) or INVISIBLE
(false). setGone: Set a view visibility to VISIBLE (true) or GONE
(false).注意: 一旦出现加载失败的情况,只有两种情况:
配置没配置好 配置没配置好,有几种情况:
- 只配置了dependencies
- 配置repositories,但是位置错了,build.gradle(Project:XXXX) 文件下的repositories有两个,一个是buildscript下面的,一个是allprojects下面的,要配置到allprojects下面才是对的。
- 版本号前面多一个v,这个是我的锅,在2.1.2版本之前都是带v的,之后(包含2.1.2)都不需要带v。 网络原因(这个就不解释了)
2.添加布局文件
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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/recyler"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
item.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="这是第1条数据"
android:textSize="24sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="name:"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="@+id/textView"
app:layout_constraintTop_toBottomOf="@id/textView" />
<TextView
android:id="@+id/name2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_10"
android:text="小明"
android:textSize="16sp"
app:layout_constraintLeft_toRightOf="@id/name"
app:layout_constraintTop_toBottomOf="@id/textView" />
<ImageView
android:id="@+id/imageView"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="@drawable/head"
android:layout_marginTop="@dimen/dp_10"
app:layout_constraintEnd_toStartOf="@+id/textView"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/dp_40"
android:text="button"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/textView" />
</androidx.constraintlayout.widget.ConstraintLayout>
3.创建实体类
Person类
public class Person {
public int id;
public String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
4.编写适配器 ☆
重点!!!
首先需要继承BaseQuickAdapter,然后BaseQuickAdapter<Status,
BaseViewHolder>第一个泛型Status是数据实体类型,第二个BaseViewHolder是ViewHolder其目的是为了支持扩展ViewHolder
MyAdapter
public class MyAdapter extends BaseQuickAdapter<Person, BaseViewHolder> {
public MyAdapter(@LayoutRes int layoutResId, @Nullable List<Person> data) {
super(layoutResId, data);
}
@Override
protected void convert(BaseViewHolder helper, Person item) {
//可链式调用赋值
helper.setText(R.id.textView, "第"+ item.getId() + "条数据")
.setText(R.id.name2, item.getName())
.setImageResource(R.id.imageView, R.drawable.head);
//获取当前条目position
//int position = helper.getLayoutPosition();
}
}
5.MainActivity
public class MainActivity extends AppCompatActivity {
RecyclerView recyclerView;
List<Person> datas;
MyAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView=findViewById(R.id.recyler);//实例化
//模拟数据
datas = new ArrayList<>();
Person person;
for (int i = 0; i < 15; i++) {
person= new Person();
person.setId(i);
person.setName("第" + i + "条内容");
datas.add(person);
}
//创建布局管理
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);
//创建适配器
adapter = new MyAdapter(R.layout.item, datas);
//给RecyclerView设置适配器
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
}
这样,一个简单的recyclerview就编写完了
6.运行
我们可以对比与之前的recyclerview的写法,在使用框架之后,我们在holder和adpter省去了大量的代码
3.item的点击事件
1.Item的点击事件
注意要放在adpter创建后
//item点击事件
adapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
Toast.makeText(MainActivity.this, "点击了第" + (position + 1) + "条条目", Toast.LENGTH_SHORT).show();
}
});
2.Item的长按事件
//条目长按事件
adapter.setOnItemLongClickListener(new BaseQuickAdapter.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(BaseQuickAdapter adapter, View view, int position) {
Toast.makeText(MainActivity.this, "长按了第" + (position + 1) + "条条目", Toast.LENGTH_SHORT).show();
return false;
}
});
3.Item的子控件点击事件
第一步,在adpter的convert里通过 helper.addOnClickListener 绑定一下子控件的控件id
(同理,长按是helper.addOnLongClickListener)
.addOnClickListener(R.id.button)//给按钮添加点击事件
第二步,我们设置
//条目子控件点击事件
adapter.setOnItemChildClickListener(new BaseQuickAdapter.OnItemChildClickListener() {
@Override
public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
Toast.makeText(MainActivity.this, "点击了第" + (position + 1) + "条条目的按钮", Toast.LENGTH_SHORT).show();
}
});
.运行
注意:设置子控件的事件,如果不在adapter中绑定,点击事件无法生效,因为无法找到你需要设置的控件。
4.多个Item子控件事件
我们可以通过判断id来判定是否是我们所设置的控件
第一步,还是在adpter里添加点击事件(这里我们给图片添加点击事件)
.addOnClickListener(R.id.imageView)//给图片添加点击事件
第二步,在刚才的单个子控件里加上判断
//条目子控件点击事件
adapter.setOnItemChildClickListener(new BaseQuickAdapter.OnItemChildClickListener() {
@Override
public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
//判断id
if (view.getId() == R.id.button) {
Toast.makeText(MainActivity.this, "点击了第" + (position + 1) + "条条目的按钮", Toast.LENGTH_SHORT).show();
} else if (view.getId() == R.id.imageView) {
Toast.makeText(MainActivity.this, "点击了第" + (position + 1) + "条条目的图片", Toast.LENGTH_SHORT).show();
}
}
});
运行
注意:如果有header的话需要处理一下position加上 headerlayoutcount。
4.列表加载动画
1.开启动画(默认为渐显效果)
//开启动画(默认为渐显效果)
adapter.openLoadAnimation();
2.该适配器提供了5种动画效果(渐显、缩放、从下到上,从左到右、从右到左)
·public static final int ALPHAIN = 0x00000001;//渐显
public static final int SCALEIN = 0x00000002;//缩放
public static final int SLIDEIN_BOTTOM = 0x00000003;//从下到上
public static final int SLIDEIN_LEFT = 0x00000004;//从左到右
public static final int SLIDEIN_RIGHT = 0x00000005;//从右到左
3.更换动画效果
//使用缩放动画
adapter.openLoadAnimation(BaseQuickAdapter.SCALEIN);
4.运行(动图不是很明显,建议亲手运行)
5.如果想自定义动画,该适配器也提供了接口
//自定义动画效果
adapter.openLoadAnimation(new BaseAnimation() {
@Override
public Animator[] getAnimators(View view) {
return new Animator[]{
ObjectAnimator.ofFloat(view, "scaleY", 1, 0.5f, 1),
ObjectAnimator.ofFloat(view, "scaleX", 1, 0.5f, 1)
};
}
});
6.动画默认只执行一次,如果想重复执行可设置
//设置重复执行动画
adapter.isFirstOnly(false);
7.首次到界面的item每次都依次执行加载动画
由于进入界面的item都是很多的速度进来的所以不会出现滑动显示的依次执行动画效果,这个时候会一起执行动画,如果觉得这样的效果不好可以使用setNotDoAnimationCount设置第一屏item不执行动画,但是如果需要依次执行动画可以重写startAnim让第一个屏幕的item动画延迟执行即可。
@Override
protected void startAnim(Animator anim, int index) {
super.startAnim(anim, index);
if (index < count)
anim.setStartDelay(index * 150);
}
5.添加头部、尾部
添加
View header = getLayoutInflater().inflate(R.layout.header, (ViewGroup) recyclerView.getParent(), false);
View footer = getLayoutInflater().inflate(R.layout.footer, (ViewGroup) recyclerView.getParent(), false);
adapter.addHeaderView(header);
adapter.addFooterView(footer);
header.xml布局文件
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="20dp"
android:background="#29B6F6">
</androidx.constraintlayout.widget.ConstraintLayout>
footer.xml布局文件
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="20dp"
android:background="#EC407A">
</androidx.constraintlayout.widget.ConstraintLayout>
删除指定view
adapter.removeHeaderView(header);
adapter.removeFooterView(footer);
删除所有
adapter.removeAllHeaderView();
adapter.removeAllFooterView();
默认出现了头部就不会显示Empty,和尾部,配置以下方法也支持同时显示:
setHeaderAndEmpty
setHeaderFooterEmpty
默认头部尾部都是占满一行,如果需要不占满可以配置:
setHeaderViewAsFlow
setFooterViewAsFlow
6.添加拖拽、滑动删除
这里adapter需要继承BaseItemDraggableAdapter
activity代码
OnItemDragListener onItemDragListener = new OnItemDragListener() {
@Override
public void onItemDragStart(RecyclerView.ViewHolder viewHolder, int pos){
}
@Override
public void onItemDragMoving(RecyclerView.ViewHolder source, int from, RecyclerView.ViewHolder target, int to) {
}
@Override
public void onItemDragEnd(RecyclerView.ViewHolder viewHolder, int pos) {
}
};
OnItemSwipeListener onItemSwipeListener = new OnItemSwipeListener() {
@Override
public void onItemSwipeStart(RecyclerView.ViewHolder viewHolder, int pos) {
}
@Override
public void clearView(RecyclerView.ViewHolder viewHolder, int pos) {
}
@Override
public void onItemSwiped(RecyclerView.ViewHolder viewHolder, int pos) {
}
@Override
public void onItemSwipeMoving(Canvas canvas, RecyclerView.ViewHolder viewHolder, float v, float v1, boolean b) {
}
};
ItemDragAndSwipeCallback itemDragAndSwipeCallback = new ItemDragAndSwipeCallback(adapter);
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(itemDragAndSwipeCallback);
itemTouchHelper.attachToRecyclerView(recyclerView);
// 开启拖拽
adapter.enableDragItem(itemTouchHelper, R.id.item, true);
adapter.setOnItemDragListener(onItemDragListener);
// 开启滑动删除
adapter.enableSwipeItem();
adapter.setOnItemSwipeListener(onItemSwipeListener);
7.自定义ViewHolder
需要继承BaseViewHolder
public class MyViewHolder extends BaseViewHolder {
private TextView mTextView;
public MyViewHolder(View view) {
super(view);
}
}
然后修改adapter的第二个泛型为自定义的ViewHolder
注意:需要单独建一个外部类继承BaseViewHolder,否则部分机型会出现ClassCastException,如果是内部类的构造方法要是public,定义的那个类也最好是public。
8.设置空布局
// 没有数据的时候默认显示该布局
mQuickAdapter.setEmptyView(getView());
关于BRVAH官方文档中还介绍了上拉加载,和分组布局以及多布局的用法,大家也可以去研究。
8.拓展框架
作者谈:
由于adapter本身能力有限,我们又不想耦合view层所以有些需求是现实不了,于是合作了一些优秀开源库,为开发者提供更多可能性。以下扩展框架都是有结合BRVAH的demo。
关于BRVAH的介绍就讲到这里啦,是不是感觉开发又轻松了一点呢
博主为了可以学到更多的Android知识,创建了一个安卓知识交流群,欢迎大佬入群,当然也欢迎和我一样的安卓小白,我们可以一起交流,最重要的是快乐水群,记得定个小目标,冲击bat