1.添加依赖
implementation 'androidx.recyclerview:recyclerview:1.2.0-alpha02'
2.在layout布局文件中声明
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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
3.在当前类中获取RecyclerView控件,并设置适配器
因为数据是无法直接传递给RecyclerView的,所以需要借助适配器来完成。 在设置Adapter之前要初始化数据源,然后通过Adapter的构造方法将数据传递给适配器, 当数据发生变化时我们只需要更新这个数据源就可以了。
public class MainActivity extends AppCompatActivity {
private ArrayList<Fruit> fruits = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView rv = findViewById(R.id.recycler_view);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(RecyclerView.VERTICAL);
rv.setLayoutManager(layoutManager);
//创建数据源
initData();
FruitAdapter adapter = new FruitAdapter(fruits);
rv.setAdapter(adapter);
}
}
RecyclerView必须要设置 layoutManager ,通过设置不同的 layoutManager 实现不同形式的列表。
常见的有:
- LinearLayoutManager 纵向/横向列表
- GridLayoutManager 网格布局
- StaggeredGridLayoutManager 瀑布流布局
4. Adapter 的编码
RecyclerView已经为我们提供了一个适配器,我们只用继承它,并且重写它的三个方法 onCreateViewHolder
、onBindViewHolder
、getItemCount
就可以了 。
- onCreateViewHolder主要是创建ViewHolder实例的, 在这个方法中可以加载子条目的布局文件, 设置子条目的点击事件
- onBindViewHolder 主要是为子条目的控件进行赋值。 会在每个子条目滚动到屏幕内的时候执行。
- getItemCount()返回的是条目数量,直接返回数据源的长度即可。
疑问: 那么onCreatViewHolder什么时候执行呢? (待理解)
我们定义的ViewHolder只需要继承Recycler的ViewHolder即可。复用holder的逻辑RecyclerView已经帮我们封装好了,所以不用像ListView那样还需要我们自己实现。
ViewHolder 构造函数的参数 itemView 其实就是 RecyclerView 子条目布局fruit_item(代码见下方)的根布局, 它就是RecyclerView列表中的子条目。 然后使用子条目fruit_item的findViewById()获取条目中的子View。
具体代码如下:
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {
private static final String TAG = "FruitAdapter";
private final ArrayList<Fruit> mFruits;
public FruitAdapter(ArrayList<Fruit> fruits) {
this.mFruits = fruits;
}
static class ViewHolder extends RecyclerView.ViewHolder {
ImageView ivFruit;
TextView tvName;
public ViewHolder(@NonNull View itemView) {
super(itemView);
ivFruit = itemView.findViewById(R.id.iv_fruit);
tvName = itemView.findViewById(R.id.tv_name);
}
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Fruit fruit = mFruits.get(position);
holder.ivFruit.setImageResource(fruit.getImageId());
holder.tvName.setText(fruit.getName());
}
@Override
public int getItemCount() {
return mFruits.size();
}
}
RecyclerView条目的布局fruit_item.xml的布局如下:
<?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"
xmlns:tool="http://schemas.android.com/tools"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv_fruit"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
/>
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tool:text="苹果"
android:layout_gravity="center_vertical"
/>
</LinearLayout>
5.设置网格列表和瀑布流
我们可以通过 LayoutManager 来设置布局的类型。
LinearLayoutManager 为列表类型的布局, 可以通过setOrientation()
来设置列表的方向。
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
//VERTICAL 竖直列表 HORIZONTAL:水平列表
layoutManager.setOrientation(RecyclerView.VERTICAL);
除了设置列表,还可以设置网格列表和瀑布流列表。
设置网格列表代码如下:
//参数二: 网格的列数
GridLayoutManager layoutManager = new GridLayoutManager(this, 3);
rv.setLayoutManager(layoutManager);
设置瀑布流
// 参数一:如果瀑布流的方向是vertical, 该参数指定了布局的列数. 如果瀑布流的方向是horizontal, 该参数指定了布局的行数
//参数二: 瀑布流的方向
StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
rv.setLayoutManager(layoutManager);
6.为RecyclerView设置点击事件
RecyclerView并没有像ListView一样为我们提供类似setOnItemClickListener的条目点击事件, 而是需要我们自己给子项具体的View去注册点击事件,所以实现起来比ListView要复杂一些。
那么为什么RecyclerView在各个方面的设计都要优于ListView, 偏偏在点击事件上却"没有处理的非常好"呢? 其实不是这样的, ListView的点击事件并不人性化, setOnItemClickListener方法注册的是子条目的点击事件, 但是如果点击的是子条目里具体的按钮呢? 虽然ListView也能实现,但是相对就比较麻烦了。 所以,RecyclerView干脆直接放弃了子条目的点击事件,所以的点击事件都由具体的View去注册。点击事件的实现方法如下:
首先, 在ViewHolder中添加fruitView变量来保存子项最外布局,
static class ViewHolder extends RecyclerView.ViewHolder {
View fruitView;
ImageView ivFruit;
TextView tvName;
ViewHolder(@NonNull View itemView) {
super(itemView);
fruitView = itemView;
ivFruit = itemView.findViewById(R.id.iv_fruit);
tvName = itemView.findViewById(R.id.tv_name);
}
}
然后在onCreateViewHolder()中注册条目或者条目中子view的点击事件。
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {
...
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item, parent, false);
final ViewHolder viewHolder = new ViewHolder(view);
//因为fruitView为子条目的最外层布局,所以该点击事件就是整个条目的点击事件
viewHolder.fruitView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (parent instanceof RecyclerView) {
int position = ((RecyclerView) parent).getChildAdapterPosition(view);
onRecyclerItemClickListener.onRecyclerItemClick(position);
}
}
});
//子项中子view的点击事件
viewHolder.ivFruit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
return viewHolder;
}
private OnRecyclerItemClickListener onRecyclerItemClickListener;
interface OnRecyclerItemClickListener {
void onRecyclerItemClick(int position);
}
@Override
public int getItemCount() {
return mFruits.size();
}
void setOnRecyclerItemClickListener(OnRecyclerItemClickListener onRecyclerItemClickListener) {
this.onRecyclerItemClickListener = onRecyclerItemClickListener;
}
...
}
参考:郭霖《第一行代码》