核心架构
|
组件 |
作用 |
|
RecyclerView |
负责视图回收和滚动管理的容器(方法setLayoutManager(),setAdapter()) |
|
Adapter |
数据与视图的桥梁,决定内容显示(必须重写onCreateViewHolder,onBindViewHolder,getItemCount) |
|
ViewHolder |
缓存视图引用(减少findViewById开销),继承RecyclerView.viewHolder |
|
LayoutManager |
控制布局排列方式(线性/网格/瀑布流) |
|
ItemDecoration |
添加Item间隔/分割线(getItemOffsets(),onDraw()) |
|
ItemAnimator |
处理增删改动画(DefaultItemAnimator,SimpleItemAnimator) |
数据Data:List<>类型数据
可滚动的列表项集合:RecyclerView
UI界面的布局管理:Recyclerview.LayoutManager
RecyclerView连接数据的适配器:RecyclerView.Adapter
每个列表项布局:XML file
显示列表项的每个控件的信息:RecyclerView.ViewHolder
每个ViewGroup都有一个布局管理器,用于定位每一个列表项的位置,可以重用对于用户不可见的列表项。
内置的布局管理器,它们都继承自LayoutManager(LinearLayoutManager线性布局,GridLayoutManager表格布局,StaggeredGridLayout瀑布形式)
Adapter作为视图和数据之间的中介,管理在数据更改时创建,更新,添加和删除列表项。
ViewHolder为适配器准备每个列表项的视图和数据,它在XML资源布局文件中指定布局,实现点击功能
RecyclerView.Adapter需要重写以下三个方法
- onCreatViewHolder():此方法通过inflate()方法将列表项item布局编译为View对象,返回以这个对象为参数的ViewHolder对象
- onBindViewHolder():此方法主要将数据渲染到列表项的ViewHolder的View控件中
- getItemCount():此方法类似与ListView的BaseAdapter适配器的getCount()方法,即数据的总条目。
RecyclerView.Adapter本身没有ListView的OnItemClick点击事件的监听器。
解决办法:
方法一:设置ViewHolder的itemView的OnClick事件监听,通过setTag()存储itemView对象信息。
方法二(推荐):Adapter类自定义内部事件接口,定义事件处理的回调方法,参数为被点击item的位置;Activity或Fragment类实现或创建该接口的对象,实现回调方法;当item被点击时调用该接口的回调方法,将位置信息传递给回调方法。
方法三:实现RecyclerView的onItemTouchListener接口,通过GestureDetectorCompat类进行手势的拦截和响应,然后GestureDetectorCompat交给实现了OnGestureListener接口的SimpleOnGestureListenter实现,调用逻辑相对较为复杂。
简单实例(MainActivity.java & activity_main.xml & ltem_layout.xml & Fruit.java & FruitAdaptet.java)
MainActivity.java
package com.example.myapplication;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
//准备数据:list数据类型为泛型,把自己建的水果类填上
private List<Fruit> fruits = new ArrayList<>(){
{
//list的add方法增加元素
add(new Fruit("苹果",R.drawable.ic_launcher_background));
add(new Fruit("苹果",R.drawable.ic_launcher_background));
add(new Fruit("苹果",R.drawable.ic_launcher_background));
add(new Fruit("苹果",R.drawable.ic_launcher_background));
add(new Fruit("苹果",R.drawable.ic_launcher_background));
add(new Fruit("苹果",R.drawable.ic_launcher_background));
add(new Fruit("苹果",R.drawable.ic_launcher_background));
add(new Fruit("苹果",R.drawable.ic_launcher_background));
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//获取视图
recyclerView = findViewById(R.id.recycle_view);
//拿到线性布局管理器
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
//给recyclerview设置线性布局管理器
recyclerView.setLayoutManager(layoutManager);
//设置方向
layoutManager.setOrientation(RecyclerView.VERTICAL);
//设置水平分割线
recyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));
//初始化水果适配器
FruitAdapter adapter = new FruitAdapter(fruits);//构造函数传参,把fruits传给FruitAdapter
//給列表设置适配器
recyclerView.setAdapter(adapter);
}
}
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"
android:orientation="vertical"
android:padding="16dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycle_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
ltem_layout.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"
android:orientation="horizontal"
android:padding="10dp"
>
<ImageView
android:id="@+id/imageView"
android:layout_width="0dp"
android:layout_height="64dp"
android:layout_weight="1"
android:layout_margin="5dp"
/>
<TextView
android:id="@+id/textview"
android:layout_width="0dp"
android:layout_height="64dp"
android:layout_weight="5"
android:textSize="18sp"
android:layout_margin="5dp"
android:gravity="center_vertical"
android:text="TextView"
/>
</LinearLayout>
Fruit.java
package com.example.myapplication;
public class Fruit {
private String name;
private int imageId;
public Fruit(String name , int imageId){
this.name = name;
this.imageId = imageId;
}
public String getName(){
return name;
}
public int getImageId(){
return imageId;
}
}
FruitAdaptet.java
package com.example.myapplication;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {
//1.定义数据成员(List)类型,用于接收Activity调用适配器时传递数据,实现数据共享
private List<Fruit> fruitsInAdapter;
//2.构造函数
public FruitAdapter(List<Fruit> fruitList) {
this.fruitsInAdapter = fruitList;
}
//3.数据的总条目
@Override
public int getItemCount() {
return fruitsInAdapter.size();
}
//4.布局:通过inflate方法将列表项item布局编译为view对象,返回以这个对象为参数的ViewHolder对象(就是创建viewholder)
@NonNull
@Override
public FruitAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout,parent,false);
return new ViewHolder(view);
}
//5.将数据渲染到列表项的ViewHolder的view控件中(就是绑定数据)
@Override
public void onBindViewHolder(@NonNull FruitAdapter.ViewHolder holder, int position) {
//给第position条目 绑定数据(从0开始计数) 对应的数据是fruitInAdapter的position个元素 里面包含名称和图片id
Fruit fruit = fruitsInAdapter.get(position);//里面包含名称和图片
holder.textView.setText(fruit.getName());
holder.imageView.setImageResource(fruit.getImageId());
}
//6.新建viewholder
public static class ViewHolder extends RecyclerView.ViewHolder {
//说明每一个条目布局上的子View的 对象一一映射关系
TextView textView;
ImageView imageView;
public ViewHolder(@NonNull View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.textview);
imageView = itemView.findViewById(R.id.imageView);
}
}
}
代码的实现逻辑
1. 初始化阶段(Adapter 创建时)
调用顺序:
-
MainActivity中创建 Adapter:FruitAdapter adapter = new FruitAdapter(fruits);将MainActivity的fruits列表通过构造函数传递给FruitAdapter的fruitsInAdapter。此时:fruitsInAdapter和fruits指向同一个 List 对象(数据共享)。
2. 列表首次加载时(RecyclerView 内部驱动)
方法调用顺序:
-
getItemCount()-
RecyclerView 首先 调用此方法获取总项数(如
fruitsInAdapter.size())。 -
作用:确定需要显示多少项。
-
-
onCreateViewHolder(parent, viewType)-
对 每一项 调用此方法,创建对应的
ViewHolder。 -
内部逻辑:
View view = LayoutInflater.inflate(R.layout.item_layout, parent, false);
return new ViewHolder(view);-
将
item_layout.xml加载为View对象。 -
创建
ViewHolder并保存子视图(TextView和ImageView)。
-
-
-
onBindViewHolder(holder, position)-
将数据绑定到
ViewHolder的视图上。 -
内部逻辑:
Fruit fruit = fruitsInAdapter.get(position); holder.textView.setText(fruit.getName()); holder.imageView.setImageResource(fruit.getImageId());-
从
fruitsInAdapter获取当前位置的数据。 -
将数据设置到
ViewHolder的控件中。
-
-
3. 滚动列表时(复用 ViewHolder)
方法调用顺序:
-
复用
ViewHolder:-
RecyclerView 复用已滚出屏幕的
ViewHolder对象(跳过onCreateViewHolder)。
-
-
直接调用
onBindViewHolder:-
重新绑定新位置的数据到复用的
ViewHolder。
-
4. 数据更新时(如添加/删除项)
调用顺序(以 notifyItemInserted() 为例):
-
MainActivity修改数据并通知 Adapter:fruits.add(new Fruit(...)); // 修改数据 adapter.notifyItemInserted(position); // 触发更新
-
Adapter 内部流程:
-
getItemCount()被重新调用(获取最新数量)。 -
对新项调用
onCreateViewHolder或复用已有ViewHolder。 -
对新项调用
onBindViewHolder绑定数据。
-

1636

被折叠的 条评论
为什么被折叠?



