文章目录
1 RecyclerView
简介
RecyclerView
是Android5.0后谷歌推出的一个用于在有限的窗口中展示大量数据集的控件,它可以称为增强版的listview
- 不仅可以轻松实现和
listview
一样的效果,同时又优化了listview
的不足之处
1.1 RecyclerView
特点
- 支持局部刷新
- 可以自定义item增删时的动画
- 能够实现item拖拽和侧滑删除等功能
- 默认已实现View的复用,而且回收机制更加完善
1.2 基本使用
- 由于
RecyclerView
不再Andriod SDK中, 所以要使用androidx.recyclerview.widget.RecyclerView
进行引用
<?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"
android:orientation="vertical"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
2 创建ReCyclerView
适配器
- 继承于
RecyclerView.Adapter<VH>
- 其中
VH
是我们创建的一个继承于RecyclerView.ViewHolder
的静态内部类
该适配器类主要有3个方法和1个自定义ViewHolder组成
onCreateViewHolder
: 创建ViewHolder
并返回,后续item布局里控件都是从ViewHolder
中取出onBindViewHolder
:通过方法提供的ViewHolder
,将数据绑定到ViewHolder
中getItemCount
:获取数据源总长度
- 使用时,设置到
RecyclerView
:recycleview.setAdapter(adapter);
2.1 FruitAdapter 实例
-
在构造函数中
public FruitAdapter(List<Fruit> fruits)
传入数据源 -
创建
ViewHolder
内部类:public class ViewHolder extends RecyclerView.ViewHolder
-
重写
RecyclerAdapter
的三个方法
- 在
public FruitAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
中进行布局填充,并保存到ViewHoler
; 可以对ViewHolder
中的控件设置监听事件 - 在
public void onBindViewHolder(@NonNull FruitAdapter.ViewHolder holder, int position)
中设置ViewHoder
中控件的内容 - 在
public int getItemCount()
中获取数据源的长度
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {
/**
* 1. FruitAdapter 继承与RecyclerAdapter,
* */
private List<Fruit> fruits;
// 1. 构造方法传入数据源
public FruitAdapter(List<Fruit> fruits) {
this.fruits = fruits;
}
@NonNull
@Override
// 创建ViewHolder实例, 将加载的布局放到构造函数中,并将View返回
public FruitAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
// 将填充的view放到viewHolder中
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_layout_staggered, parent, false);
ViewHolder holder = new ViewHolder(view);
// 1. 在创建的时候进行点击事件
// 从viewHolder中获取子空间, 添加点击事件
// 1.1 子布局的点击事件
holder.getFruitView().setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view1) {
// 获取点击的位置,定位数组并输出信息
int adapterPosition = holder.getAdapterPosition();
Fruit fruit = fruits.get(adapterPosition);
Toast.makeText(view1.getContext(), "点击的布局,其中内容为: " + fruit.getName(), Toast.LENGTH_SHORT).show();
}
});
// 1.2 获取图片的点击事件
holder.getFruitImage().setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view2) {
int adapterPosition = holder.getAdapterPosition();
Fruit fruit = fruits.get(adapterPosition);
Toast.makeText(view2.getContext(), "点击图片的水果名称为: " + fruit.getName(), Toast.LENGTH_SHORT).show();
}
});
// 1.3 为文本框指定点击事件
holder.getFruitName().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view3) {
String name = ((TextView)view3.findViewById(R.id.fruit_name)).getText().toString();
Toast.makeText(view3.getContext(), name, Toast.LENGTH_SHORT).show();
}
});
return holder;
}
@Override
// 2. 每个子项滚动到屏幕内执行,通过 positon 得到当前项的实例,然后显示图片和文字,填充布局
public void onBindViewHolder(@NonNull FruitAdapter.ViewHolder holder, int position) {
Fruit fruit = fruits.get(position);
holder.getFruitImage().setImageResource(fruit.getImageID());
holder.getFruitName().setText(fruit.getName());
holder.getFruitPrice().setText("$" + (double)fruit.getPrice()/100 + "/Kg");
}
@Override
public int getItemCount() {
return fruits.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
// 添加ViewHolder中的控件
private View fruitView;
private ImageView fruitImage;
private TextView fruitName;
private TextView fruitPrice;
public ViewHolder(@NonNull View itemView) {
super(itemView);
this.fruitView = itemView;
this.fruitImage = itemView.findViewById(R.id.fruit_image);
this.fruitName = itemView.findViewById(R.id.fruit_name);
this.fruitPrice = itemView.findViewById(R.id.fruit_price);
}
public void setFruitView(View fruitView) {
this.fruitView = fruitView;
}
public void setFruitImage(ImageView fruitImage) {
this.fruitImage = fruitImage;
}
public void setFruitName(TextView fruitName) {
this.fruitName = fruitName;
}
public void setFruitPrice(TextView fruitPrice) {
this.fruitPrice = fruitPrice;
}
public ImageView getFruitImage() {
return fruitImage;
}
public TextView getFruitName() {
return fruitName;
}
public TextView getFruitPrice() {
return fruitPrice;
}
public View getFruitView() {
return fruitView;
}
}
}
3 为适配器中的控件指定布局
- 相对于
ListView
只能使用线性布局的局限,RecyclerView
能自定义布局,并通过不同的布局管理器来控制item的排列顺序,负责item元素的布局和复用
RecyclerView提供了三种布局管理器:
LinearLayoutManager
:线性布局,以垂直戒水平滚动列表方式显示项目
// 5.1 创建垂直的线性布局
LinearLayoutManager layoutManager = new LinearLayoutManager(MainActivity.this);
recyclerView.setLayoutManager(layoutManager);
GridLayoutManager
:网格布局,在网格中显示项目
// 5.2 创建横向的线性布局
LinearLayoutManager linearLayoutManagerHorizontal = new LinearLayoutManager(this);
linearLayoutManagerHorizontal.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(linearLayoutManagerHorizontal);
StaggeredGridLayoutManager
:瀑布流布局,在分散对齐网格中显示项目
// 5.3 创建瀑布布局
StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(staggeredGridLayoutManager);
4 布局layout文件
4.1 垂直线性子布局xml文件
<?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="wrap_content">
<ImageView
android:layout_width="100dp"
android:layout_height="80dp"
android:id="@+id/fruit_image"
android:src="@drawable/apple"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/fruit_name"
android:text="name"
android:textSize="30sp"
android:textColor="#000000"
android:layout_gravity="center_vertical"
android:layout_marginLeft="20dp"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/fruit_price"
android:text="name"
android:textSize="30sp"
android:textColor="#ff0000"
android:layout_gravity="center_vertical"
android:layout_marginLeft="40dp"
/>
</LinearLayout>
4.2 水平线性子布局xml文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="120dp"
android:layout_height="wrap_content">
<ImageView
android:layout_width="100dp"
android:layout_height="80dp"
android:layout_gravity="center_horizontal"
android:id="@+id/fruit_image"
android:src="@drawable/apple"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/fruit_name"
android:text="name"
android:textSize="24sp"
android:textColor="#000000"
android:layout_gravity="center"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/fruit_price"
android:text="12.00"
android:textSize="12sp"
android:textColor="#ff0000"
android:layout_gravity="center"
/>
</LinearLayout>
4.3 瀑布布局xml文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_margin="5dp"
android:layout_height="wrap_content">
<ImageView
android:layout_width="100dp"
android:layout_height="80dp"
android:layout_gravity="center_horizontal"
android:id="@+id/fruit_image"
android:src="@drawable/apple"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/fruit_name"
android:text="name"
android:textSize="24sp"
android:textColor="#000000"
android:layout_gravity="center"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/fruit_price"
android:text="12.00"
android:textSize="12sp"
android:textColor="#ff0000"
android:layout_gravity="center"
/>
</LinearLayout>
5 Fruit封装数据类
package com.hlq.sz_ch06_recycler_view;
public class Fruit {
private int imageID;
private String name;
private long price;
public void setImageID(int imageID) {
this.imageID = imageID;
}
public void setName(String name) {
this.name = name;
}
public void setPrice(long price) {
this.price = price;
}
public int getImageID() {
return imageID;
}
public String getName() {
return name;
}
public long getPrice() {
return price;
}
public Fruit(int imageID, String name, long price) {
this.imageID = imageID;
this.name = name;
this.price = price;
}
public Fruit() {
}
}
6 MainActivity 主界面
package com.hlq.sz_ch06_recycler_view;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
import android.os.Bundle;
import android.widget.LinearLayout;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 1. 绑定控件
recyclerView = this.findViewById(R.id.recycler_view);
// 2. 准备数据
List<Fruit> fruits = new ArrayList<>();
for (int i = 0; i < 10; ++i) {
Fruit pineApple = new Fruit(R.drawable.pineapple, "菠萝", 1690);
fruits.add(pineApple);
Fruit mango = new Fruit(R.drawable.mango, "芒果", 2990);
fruits.add(mango);
Fruit grape = new Fruit(R.drawable.grape, "葡萄", 1990);
fruits.add(grape);
Fruit pomegranate = new Fruit(R.drawable.pomegranate, "石榴", 1500);
fruits.add(pomegranate);
Fruit apple = new Fruit(R.drawable.apple, "苹果", 2000);
fruits.add(apple);
Fruit watermelon = new Fruit(R.drawable.watermelon, "西瓜", 2880);
fruits.add(watermelon);
Fruit orange = new Fruit(R.drawable.orange, "橘子", 1880);
fruits.add(orange);
}
// 3. 设计子布局
// 4. 创建自定义适配器
FruitAdapter adapter = new FruitAdapter(fruits);
// 5. 创建布局管理器,将RecyclerView中的布局以布局管理器中的布局进行管理
// // 5.1 创建垂直的线性布局
// LinearLayoutManager layoutManager = new LinearLayoutManager(MainActivity.this);
// recyclerView.setLayoutManager(layoutManager);
// // 5.2 创建横向的线性布局
// LinearLayoutManager linearLayoutManagerHorizontal = new LinearLayoutManager(this);
// linearLayoutManagerHorizontal.setOrientation(LinearLayoutManager.HORIZONTAL);
// recyclerView.setLayoutManager(linearLayoutManagerHorizontal);
// 5.3 创建瀑布布局
StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(staggeredGridLayoutManager);
// 6 绑定 布局-控制-数据的适配器
recyclerView.setAdapter(adapter);
}
}