RecyclerView是一种新的视图组,目标是为任何基于适配器的视图提供相似的渲染方式。它被作为ListView和GridView控件的继承者,在最新的support-V7版本中提供支持。
有了 ListView、GridView 为什么还需要 RecyclerView 这样的控件?
优点 :RecyclerView 提供了一种插拔式的体验,高度的解耦,异常的灵活,通过设置它提供的不同LayoutManager,ItemDecoration , ItemAnimator 实现 ListView,GridView,瀑布流的效果。
- 你想要控制其显示的方式,请通过布局管理器LayoutManager
- 你想要控制 Item 间的间隔(可绘制),请通过 ItemDecoration
- 你想要控制 Item 增删的动画,请通过 ItemAnimator
缺点 :缺少 Item 点击事件,没有添加头部 View 基本使用
简单使用
- 初始化控件 :mRecyclerView = findView(R.id.id_recyclerview);
- 设置布局管理器:mRecyclerView.setLayoutManager(layout);
- 设 置 adapter:mRecyclerView.setAdapter(adapter)
布局管理器
RecyclerView.LayoutManager,这是一个抽象类,系统提供了 3 个实现类:
- LinearLayoutManager 现行管理器,支持横向、纵向。
- GridLayoutManager 网格布局管理器
- StaggeredGridLayoutManager 瀑布流式布局管理器
线性布局
rv.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,true));
- 第一个参数是上下文
- 第二个参数是我们的布局管理器横向展示还是纵向展示
- 第三个参数是 true 从末尾展示,相反从头展示
网格布局
rv.setLayoutManager(new GridLayoutManager(this,3,GridLayoutManager.HORIZONTAL,true));
- 第一个参数是上下文
- 第二个参数相对第三个参数而讲 如果是横向的代表三列 如果是竖直的代表三行
- 第三个参数我们的布局管理器横向展示还是纵向展示
- 第四个参数是 true 从末尾展示,相反从头展示
瀑布流管理器
new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL)
注意:在使用瀑布流管理器的时候 需要给每个 item 随机数设置相应高度
我们可以在viewholder 中对 imageview 动态设置高度
RecyclerView.Adapter 适配器
创建适配器类继承RecycleView的Adapter,步骤为:
- 继承RecyclerView.Adapter,并且在Adapter里面声明ViewHolder类继承RecyclerView.ViewHolder,最后把自己的ViewHolder类丢进自己的Adapter类的泛型中去。
- 在自定义ViewHolder类的构造方法中可以通过ID找到布局的控件,控件需要声明为自定义ViewHolder类的成员变量。
- 实现RecyclerView.Adapter的所有未实现的函数,onCreateViewHolder主要负责加载布局(加载的时候注意要把父布局写到参数里去),创建自定义ViewHolder类的对象;onBindViewHolder主要负责把数据设置到Item的控件中;getItemCount主要负责得到数据的数目。
- 最好把数据声明为成员变量,在构造函数里面传进来。
- 由于RecycleView原生不支持点击事件,需要自己添加接口进行回调。
瀑布流布局实例
ps:其他布局我已经再其他案例中应用过,瀑布流这种布局目前没有练习。
案例只要通过本地图片加载显示,不用考虑内存机制,图片加载框架。
效果图如下:
子布局
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="1dp"
card_view:cardBackgroundColor="@color/white"
card_view:cardCornerRadius="8dp"
android:elevation="8dp"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<ImageView
android:id="@+id/masonry_item_img"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="centerCrop" />
<TextView
android:id="@+id/masonry_item_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
</androidx.cardview.widget.CardView>
MainActivity.java
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private List<Product> productList=new ArrayList<Product>();
private Product mProduct;
// 展示的文字
private String[] texts = new String[] {
"已知花意,未见其花。已见其花,未闻花名。", "此生无悔入四月,来世愿做友人。",
"此生无悔入夏目,来世愿做帐中妖。", "安兹王屠帝,号天下于此。",
"如果幸福有颜色的话,那一定的被末日所染红的蓝色", "吾王剑之所指,吾等心之所向。",
"无论在什么地方,什么时候,在我们的头顶都是同样悠远的天穹,就好像是永远都无法分开的羁绊","镜子里显示出来的永远只是真实的影像,而不是真实的自己。",
"人类的心里住着一只野兽,纯粹,凶猛,无法驯养,那是一只叫做“嫉妒”的野兽" ,"如果我闭上了双眼,看到的是黑暗的话,那么当我睁开眼睛去看这个世界的时候,是否会是一片光明?",
"我想成为一个温柔的人,因为曾被温柔的人那样对待,深深了解那种被温柔相待的感觉。","如果时光可以倒流 我还是会选择认识你 虽然会伤痕累累 但是心中的温暖记忆是谁都无法给与的 谢谢你来过我的世界",
"无论在哪里遇到你,我都会喜欢上你","只要有你在,我就无所不能。",
};
private int[] photo = new int[] { R.mipmap.t1,R.mipmap.t2,R.mipmap.t3,R.mipmap.t4,R.mipmap.t5,R.mipmap.t6,R.mipmap.t7,R.mipmap.t8,R.mipmap.t9,
R.mipmap.t10,R.mipmap.t11,R.mipmap.t12,R.mipmap.t13,R.mipmap.t14};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView= (RecyclerView) findViewById(R.id.recycler);
//设置layoutManager
recyclerView.setLayoutManager(new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL));
//设置adapter
initData();
MasonryAdapter adapter=new MasonryAdapter(productList);
recyclerView.setAdapter(adapter);
//设置item之间的间隔
SpacesItemDecoration decoration=new SpacesItemDecoration(16);
recyclerView.addItemDecoration(decoration);
}
private void initData() {
for (int i=0;i<texts.length;i++){
mProduct=new Product(photo[i],texts[i]);
productList.add(mProduct);
}
}
public class SpacesItemDecoration extends RecyclerView.ItemDecoration {
private int space;
public SpacesItemDecoration(int space) {
this.space=space;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
outRect.left=space;
outRect.right=space;
outRect.bottom=space;
if(parent.getChildAdapterPosition(view)==0){
outRect.top=space;
}
}
}
}
适配器
public class MasonryAdapter extends RecyclerView.Adapter<MasonryAdapter.MasonryView> {
private List<Product> products;
public MasonryAdapter(List<Product> list) {
products = list;
}
@Override
public MasonryView onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.masonry_item, viewGroup, false);
return new MasonryView(view);
}
@Override
public void onBindViewHolder(MasonryView masonryView, int position) {
masonryView.imageView.setImageResource(products.get(position).getImg());
masonryView.textView.setText(products.get(position).getTitle());
}
@Override
public int getItemCount() {
return products.size();
}
public static class MasonryView extends RecyclerView.ViewHolder {
ImageView imageView;
TextView textView;
public MasonryView(View itemView) {
super(itemView);
imageView = (ImageView) itemView.findViewById(R.id.masonry_item_img);
textView = (TextView) itemView.findViewById(R.id.masonry_item_title);
}
}
}