RecyclerView是Android一个更强大的控件,其不仅可以实现和ListView同样的效果,还有优化了ListView中的各种不足。其可以实现数据纵向滚动,也可以实现横向滚动(ListView做不到横向滚动)。接下来讲解RecyclerView的用法。
RecyclerView 基本用法
因为RecyclerView属于新增的控件,Android将RecyclerView定义在support库里。若要使用RecyclerView,第一步是要在build.gradle中添加对应的依赖库。
添加RecyclerView 依赖库
在app/build.gradle中的dependencies闭包添加以下内容:
implementation ‘com.android.support:recyclerview-v7:27.1.1’
(可能会导包失败,找不到类,是因为上面的是旧路径依赖,需要导入新路径依赖,即Androidx对应的路径
implementation ‘androidx.recyclerview:recyclerview:1.0.0’
具体参考,主要讲为什么会找不到RecyclerView类:
https://blog.csdn.net/xjxdaima/article/details/100078857?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param
)
然后点击顶部的Sync Now进行同步
修改 activity_main.xml
<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"><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/recycler_view"android:layout_width="match_parent"android:layout_height="match_parent"/></LinearLayout>
由于RecyclerView不是内置在系统SDK中,需要把其完整的包名路径写出来
新建 Fruit.java 此类为数据源中的domain类
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;
}}
新建 fruit_item.xml
创建ImageView来显示水果图片,TextView来显示水果名字。
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/fruit_image"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/fruitname"android:layout_gravity="center_vertical"android:layout_marginLeft="10dp"/>
</LinearLayout>
新增适配器 FruitAdapter,直接创建FruitAdapter.java文件
为RecyclerView新增适配器FruitAdapter,并让其继承于RecyclerView.Adapter,把泛型指定为FruitAdapter.ViewHolder。
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {
private List<Fruit> mFruitList; //数据源,在new此类的时候传入//静态内部类, 每个条目对应的布局static class ViewHolder extends RecyclerView.ViewHolder{ImageView fruitImage;TextView fruitName;public ViewHolder (View view){super(view);fruitImage = (ImageView) view.findViewById(R.id.fruit_image);fruitName = (TextView) view.findViewById(R.id.fruitname);}}//FruitAdapter的构造方法,加入了数据源参数,在构造的时候赋值给mFruitListpublic FruitAdapter (List <Fruit> fruitList){mFruitList = fruitList;}//用于创建ViewHolder实例,并把加载的布局传入到ViewHolder的构造函数去@Overridepublic ViewHolder onCreateViewHolder(ViewGroup parent, int viewType){View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item,parent,false);ViewHolder holder = new ViewHolder(view);return holder;}//是用于对子项的数据进行赋值,会在每个子项被滚动到屏幕内时执行。position得到当前项的Fruit实例@Overridepublic void onBindViewHolder(ViewHolder holder, int position){Fruit fruit = mFruitList.get(position);holder.fruitImage.setImageResource(fruit.getImageId());holder.fruitName.setText(fruit.getName());}//返回RecyclerView的子项数目@Overridepublic int getItemCount(){return mFruitList.size();}
定义内部类ViewHolder,并继承RecyclerView.ViewHolder。传入的View参数通常是RecyclerView子项的最外层布局。
FruitAdapter构造函数,用于把要展示的数据源传入,并赋予值给全局变量mFruitList。
FruitAdapter继承RecyclerView.Adapter。因为必须重写onCreateViewHolder(),onBindViewHolder()和getItemCount()三个方法:
onCreateViewHolder()用于创建ViewHolder实例,并把加载的布局传入到构造函数去,再把ViewHolder实例返回。
onBindViewHolder()则是用于对子项的数据进行赋值,会在每个子项被滚动到屏幕内时执行。position得到当前项的Fruit实例。
getItemCount()返回RecyclerView的子项数目。
修改 MainActivity.java
public class MainActivity extends AppCompatActivity {private List<Fruit> fruitList = new ArrayList<>();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//初始化数据initFruits();//RecyclerView获取他的对象RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);//LayoutManager用于指定RecyclerView的布局方式LinearLayoutManager layoutManager = new LinearLayoutManager(this);//给layoutManager 的展示方式设置为竖直方向
layoutManager .setOrientation(LinearLayoutManager.VERTICAL);recyclerView.setLayoutManager(layoutManager);FruitAdapter adapter = new FruitAdapter(fruitList);recyclerView.setAdapter(adapter);}//初始化数据private void initFruits() {for (int i = 0; i < 2; i++) {Fruit apple = new Fruit("Apple", R.drawable.apple_pic);fruitList.add(apple);Fruit banana = new Fruit("Banana", R.drawable.banana_pic);fruitList.add(banana);Fruit orange = new Fruit("Orange", R.drawable.orange_pic);fruitList.add(orange);Fruit watermelon = new Fruit("Watermelon", R.drawable.watermelon_pic);fruitList.add(watermelon);Fruit pear = new Fruit("Pear", R.drawable.pear_pic);fruitList.add(pear);Fruit grape = new Fruit("Grape", R.drawable.grape_pic);fruitList.add(grape);Fruit pineapple = new Fruit("Pineapple", R.drawable.pineapple_pic);fruitList.add(pineapple);Fruit strawberry = new Fruit("Strawberry", R.drawable.strawberry_pic);fruitList.add(strawberry);Fruit cherry = new Fruit("Cherry", R.drawable.cherry_pic);fruitList.add(cherry);Fruit mango = new Fruit("Mango", R.drawable.mango_pic);fruitList.add(mango);}}}
LayoutManager用于指定RecyclerView的布局方式。LinearLayoutManager指的是线性布局。
运行效果:

修改RecyclerView 显示效果
横向滚动
通过调用setOrientation()把布局的排列方向改为水平排列。
得益于RecyclerView的设计,我们可以通过LayoutManager实现各种不同的排列方式的布局。
运行结果:

除了LinearLayoutManager,RecyclerView还提供了GridLayoutManager(网格布局)和StaggeredGridLayoutManager(瀑布流布局)
GridLayoutManager
GridLayoutManager(网格布局)
修改MainActivity.java
修改 MainActivity.java,把
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
换成
GridLayoutManager layoutManager = new GridLayoutManager(this,5);
GridLayoutManager (Context context, int spanCount)
Context: Current context, will be used to access resources.
spanCount int: The number of columns in the grid(网格的列数)
运行结果:

StaggeredGridLayoutManager
StaggeredGridLayoutManager(瀑布流布局)
修改fruit_item.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="5dp"><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/fruit_image"android:layout_gravity="center_horizontal"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/fruitname"android:layout_gravity="left"android:layout_marginTop="10dp"/></LinearLayout>
把LinearLayout的宽度设为match_parent是因为瀑布流的宽度是 根据布局的列数来自动适配的,而不是固定值 。(GridLayoutManager也是 根据布局的列数来自动适配的)
StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
StaggeredGridLayoutManager传入2个参数,第一个是布局的列数,第二个是布局的排列方向。
运行效果:

GridLayoutManager和StaggeredGridLayout的区别


上图是GridLayoutManager,下图是StaggeredGridLayout。
当从显示效果来看,已经一目了然。
GridLayoutManager是会固定高度的,所以会留下很多空白区域。
相反,StaggeredGridLayout并不会固定高度,以至于就算子项的高度不一致,下一行的会自动靠拢上一行。
RecyclerView 的点击事件
修改 FruitAdapter.java
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {private List<Fruit> mFruitList;static class ViewHolder extends RecyclerView.ViewHolder{View fruitView;ImageView fruitImage;TextView fruitName;public ViewHolder (View view){super(view);fruitView = view;fruitImage = (ImageView) view.findViewById(R.id.fruit_image);fruitName = (TextView) view.findViewById(R.id.fruitname);}}public FruitAdapter (List <Fruit> fruitList){mFruitList = fruitList;}@Overridepublic ViewHolder onCreateViewHolder(ViewGroup parent, int viewType){View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item,parent,false);final ViewHolder holder = new ViewHolder(view);holder.fruitView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {int position = holder.getAdapterPosition();Fruit fruit = mFruitList.get(position);Toast.makeText(view.getContext(), "you clicked view" + fruit.getName(), Toast.LENGTH_SHORT).show();}});holder.fruitImage.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {int position = holder.getAdapterPosition();Fruit fruit = mFruitList.get(position);Toast.makeText(view.getContext(), "you clicked image" + fruit.getName(), Toast.LENGTH_SHORT).show();}});return holder;}...}
修改ViewHolder,添加fruitView变量来保存子项最外层布局的实例。
运行效果:


















