参考 《第一行代码》第二版
使用的工具
现在android项目使用的 android studio 来进行开发,开发的语言现在推荐的是 kotlin, 不过这里还是先使用 Java 来开发
-
AndroidStudio 版本: Android Studio Iguana | 2023.2.1
-
项目语言: Java
-
JDK版本: 17
-
对应的android版本:12
在看 RecycleView 之前可以先参考 Android中ListView的使用 - 掘金 (juejin.cn)
添加依赖
想要使用 RecycleView 需要先添加对应的依赖,在 app 项目下的 build.gralde 文件中添加如下内容
dependencies {
......
implementation 'androidx.recyclerview:recyclerview:1.3.2'
}
RecycleView的使用示例
最终的效果如下图所示
还有很多行数据,可以滑动显示
这个示例中主要包含
- MainActivity 是项目的主 Activity
- activity_main.xml 主Activity对应的配置文件
- fruit_item.xml 是 RecycleView 中每一项元素的布局文件
- CusRecycleAdapter 是 RecycleView 中对应的 Adapter
activity_main.xml
主布局文件中就使用了一个 RecycleView
<?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="match_parent"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycle_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
fruit_item.xml
- fruit_item.xml 是对于 RecycleView 中每一项元素的布局
- 每一项元素的根布局是 LinearLayout, 排列方向 orientation="horizontal",即是水平排列,因为这个布局里面包含两个元素,一个是图片(ImageView),另外一个是文本(TextView),因为是水平排列,所以左侧是图片,右侧是文字
<?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">
<ImageView
android:id="@+id/fruit_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/fruit_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_gravity="center_vertical"/>
</LinearLayout>
CusRecycleAdapter
和 ListView 中的 Adapter 一样,RecycleView 也有一个 Adapter,起到的作用就是将单项数据绑定到对应的布局上(在这个例子中就是将单项数据绑定到 fruit_view.xml 对应的布局上)
package com.example.ademo.adapter;
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 com.example.ademo.R;
import com.example.ademo.vo.EachItem;
import java.util.List;
public class CusRecycleAdapter extends RecyclerView.Adapter<CusRecycleAdapter.ViewHolder> {
// 保存需要展示的所有数据
private List<EachItem> list;
// 构造 RecycleAdapter 的时候需要将需要展示的所有数据传递进来
public CusRecycleAdapter(List<EachItem> list) {
this.list = list;
}
// ViewHolder 顾名思义就是持有 View 的,持有什么 View 呢? 其实就是
// RecycleView 中单个元素所对应的布局,这里的 View 其实是 ViewGroup 类型
static class ViewHolder extends RecyclerView.ViewHolder {
ImageView imageView;
TextView textView;
/**
* 这里的 View 一般就是 RecyclerView 子项的最外层布局, 在这个例子中其实就是 fruit_item 对应的布局
* 对应的就是 onCreateViewHolder 创建的 ViewHolder 中的 View
* * @param itemView
*/
public ViewHolder(@NonNull View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.fruit_image);
textView = itemView.findViewById(R.id.fruit_name);
}
}
/**
* onCreateViewHolder 的作用其实就是加载每一项元素的布局,这里加载的布局得到了 View
* 然后将 View 存储在 ViewHolder 中,然后返回 ViewHolder
* * @return */ @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;
}
/**
* onBindViewHolder()方法是用于对RecyclerView子项的数据进行赋值的,会在每个子项被滚动到屏幕内的时候执行
*/
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
EachItem eachItem = list.get(position);
holder.imageView.setImageResource(eachItem.getImageId());
holder.textView.setText(eachItem.getName());
}
@Override
public int getItemCount() {
return list.size();
}
}
MainActivity
接下来就是使用 RecycleView 的主 Activity 了
package com.example.ademo;
import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.example.ademo.adapter.CusRecycleAdapter;
import com.example.ademo.vo.EachItem;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private List<EachItem> list = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.d("MainActivity", "开始创建主Activity" + this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initItem();
RecyclerView recyclerView = findViewById(R.id.recycle_view);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(linearLayoutManager);
CusRecycleAdapter adapter = new CusRecycleAdapter(list);
recyclerView.setAdapter(adapter);
}
/**
* 初始化明细数据
*/
private void initItem() {
for (int i = 0; i < 20; i++) {
EachItem eachItem = new EachItem("水果" + i, R.drawable.ic_launcher_background);
list.add(eachItem);
}
}
}
可以看到 RecycleView 和 ListView 的区别是使用 RecycleView 时除了要设置 Adapter 之外,还需要设置LayoutManager,这也是 RecycleView 的强大之处,可以自定义设置外层布局
RecycleView点击事件
RecyclerView 没有提供类似于 setOnItemClickListener() 这样的注册监听器方法,需要我们自己给子项具体的View去注册点击事件,我们在上面的例子中改造,点击每一项的时候都弹出对应的内容,主要是修改 Adapter 类
package com.example.ademo.adapter;
import android.util.Log;
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 com.example.ademo.R;
import com.example.ademo.vo.EachItem;
import java.util.List;
public class CusRecycleAdapter extends RecyclerView.Adapter<CusRecycleAdapter.ViewHolder> {
private List<EachItem> list;
public CusRecycleAdapter(List<EachItem> list) {
this.list = list;
}
static class ViewHolder extends RecyclerView.ViewHolder {
ImageView imageView;
TextView textView;
/**
* 这里的 View 一般就是 RecyclerView 子项的最外层布局, 在这个例子中其实就是 fruit_item 对应的布局
* 对应的就是 onCreateViewHolder 创建的 ViewHolder 中的 View
* * @param itemView
*/
public ViewHolder(@NonNull View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.fruit_image);
textView = itemView.findViewById(R.id.fruit_name);
}
}
/**
* onCreateViewHolder 的作用其实就是加载每一项元素的布局,这里加载的布局得到了 View
* 然后将 View 存储在 ViewHolder 中,然后返回 ViewHolder
* * @return */ @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);
viewHolder.imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int bindingAdapterPosition = viewHolder.getBindingAdapterPosition();
EachItem eachItem = list.get(bindingAdapterPosition);
Log.d("onCreateViewHolder", "图片点击: " + eachItem.getName());
}
});
viewHolder.textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int bindingAdapterPosition = viewHolder.getBindingAdapterPosition();
EachItem eachItem = list.get(bindingAdapterPosition);
Log.d("onCreateViewHolder", "文本点击: " + eachItem.getName());
}
});
return viewHolder;
}
/**
* onBindViewHolder()方法是用于对RecyclerView子项的数据进行赋值的,会在每个子项被滚动到屏幕内的时候执行
*/
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
EachItem eachItem = list.get(position);
holder.imageView.setImageResource(eachItem.getImageId());
holder.textView.setText(eachItem.getName());
}
@Override
public int getItemCount() {
return list.size();
}
}