一. 前言 1. 使用方式 ① build.gradle(Module:app)中添加依赖。
1 implementation 'androidx.recyclerview:recyclerview:1.0.0'
2. 布局文件中搜索RecyclerView下载
2. 介绍 RecyclerView
是 Google 用来替代 ListView
与 GridView
的控件。默认提供了三个 LayoutManager
。
LinearLayoutManager:线性布局管理器,支持横向,纵向。
GridLayoutManager:网格布局管理器。
StaggeredGridLayoutManager:瀑布流式布局管理器。
二. RecyclerView.Adapter RecyclerView使用的适配器需要继承
RecyclerView.Adapter,RecyclerView.ViewHolder本身是一个抽象类,我们往往自己继承这个抽象类,然后绑定我们的布局控件对象。继承该类时必须传入一个itemView,表示这个item显示的View。
在 RecyclerView.Adapter中必须实现的三个方法:
1 2 3 4 5 6 7 8 public int getItemCount () ;public RecyclerView.ViewHolder onCreateViewHolder (@NonNull ViewGroup parent,int viewType) ; public void onBindViewHolder (@NonNull RecyclerView.ViewHolder holder,int position) ;
三. 四个小例子 Github地址
1. LinearLayoutManager - 纵向
① 自定义的RecyclerView类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 public class XLRecyclerView extends RecyclerView { private OnItemClickListener listener; public XLRecyclerView (@NonNull Context context) { super (context); init(); } public XLRecyclerView (@NonNull Context context, @Nullable AttributeSet attrs) { super (context, attrs); init(); } private void init () { LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext()); linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); this .setLayoutManager(linearLayoutManager); this .setAdapter(new MyAdapter(DataUtil.loadData(getContext()))); } class MyAdapter extends RecyclerView .Adapter { private List<FriendBean> friends; public MyAdapter (List<FriendBean> friends) { this .friends = friends; } @NonNull @Override public ViewHolder onCreateViewHolder (@NonNull ViewGroup parent, int viewType) { View inflate = LayoutInflater.from(parent.getContext()).inflate(R.layout.friend_layout, parent, false ); return new MyViewHolder(inflate); } @Override public void onBindViewHolder (@NonNull ViewHolder holder, final int position) { final FriendBean friend = friends.get(position); MyViewHolder myViewHolder = (MyViewHolder) holder; myViewHolder.icon_view.setImageResource(friend.getIcon_id()); myViewHolder.name_view.setText(friend.getName()); myViewHolder.mode_view.setText(friend.getMode()); myViewHolder.icon_view.setOnClickListener(new OnClickListener() { @Override public void onClick (View v) { if (listener != null ){ listener.onItemClick(position); } } }); } @Override public int getItemCount () { return friends.size(); } } static class MyViewHolder extends RecyclerView .ViewHolder { ImageView icon_view; TextView name_view; TextView mode_view; public MyViewHolder (@NonNull View itemView) { super (itemView); icon_view = itemView.findViewById(R.id.friend_icon); name_view = itemView.findViewById(R.id.friend_name); mode_view = itemView.findViewById(R.id.friend_mode); } } public interface OnItemClickListener { void onItemClick (int position) ; } public void setOnItemClickListener (OnItemClickListener listener) { this .listener = listener; } }
② item的布局文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:paddingTop="10dp" > <LinearLayout android:id="@+id/main" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingBottom="10dp" android:background="#009900" > <swu.xl.linear_ver.XLImageView android:id="@+id/friend_icon" android:layout_width="100dp" android:layout_height="100dp" android:src="@drawable/ic_launcher_foreground" android:scaleType="fitXY" /> <LinearLayout android:layout_marginStart="20dp" android:layout_width="0dp" android:layout_height="match_parent" android:orientation="vertical" android:layout_weight="1" > <TextView android:layout_marginTop="15dp" android:id="@+id/friend_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textStyle="bold" android:textSize="20sp" android:text="姓名" /> <TextView android:layout_marginTop="10dp" android:id="@+id/friend_mode" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="18sp" android:text="动态" /> </LinearLayout > </LinearLayout > <View android:layout_width="match_parent" android:layout_height="3dp" android:background="#000000" android:layout_below="@+id/main" /> </RelativeLayout >
③ 模型类,以及数据加载类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public class FriendBean { private int icon_id; private String name; private String mode; public FriendBean (int icon_id, String name, String mode) { this .icon_id = icon_id; this .name = name; this .mode = mode; } public int getIcon_id () { return icon_id; } public void setIcon_id (int icon_id) { this .icon_id = icon_id; } public String getName () { return name; } public void setName (String name) { this .name = name; } public String getMode () { return mode; } public void setMode (String mode) { this .mode = mode; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 public class DataUtil { public static List<FriendBean> loadData (Context context) { int [] icon_ids = new int []{ R.drawable.friend1, R.drawable.friend2, R.drawable.friend3, R.drawable.friend4, R.drawable.friend5, R.drawable.friend6, R.drawable.friend7, R.drawable.friend8, R.drawable.friend9, R.drawable.friend10 }; String[] names = context.getResources().getStringArray(R.array.name); String[] modes = context.getResources().getStringArray(R.array.mode); List<FriendBean> friends = new ArrayList<>(); for (int i = 0 ; i < 10 ; i++) { FriendBean friend = new FriendBean(icon_ids[i],names[i],modes[i]); friends.add(friend); } return friends; } }
④ 具体使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout 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" tools:context =".MainActivity" > <swu.xl.linear_ver.XLRecyclerView android:id="@+id/recycler" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class MainActivity extends AppCompatActivity { @Override protected void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); XLRecyclerView recyclerView = findViewById(R.id.recycler); recyclerView.setOnItemClickListener(new XLRecyclerView.OnItemClickListener() { @Override public void onItemClick (int position) { Toast.makeText(MainActivity.this , DataUtil.loadData(MainActivity.this ).get(position).getName(), Toast.LENGTH_SHORT).show(); } }); } }
2. LinearLayoutManager - 横向
只需要修改一处地方:
1 2 3 4 5 6 7 8 9 private void init () { LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext()); linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); this .setLayoutManager(linearLayoutManager); this .setAdapter(new MyAdapter(DataUtil.loadData(getContext()))); }
3. GridLayoutManager
① 修改了item布局文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="10dp" > <LinearLayout android:id="@+id/main" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#009900" android:orientation="vertical" > <swu.xl.grid.XLImageView android:id="@+id/friend_icon" android:layout_width="100dp" android:layout_height="100dp" android:src="@drawable/ic_launcher_foreground" android:scaleType="fitXY" /> <LinearLayout android:layout_marginStart="20dp" android:layout_width="wrap_content" android:layout_height="0dp" android:orientation="vertical" android:layout_weight="1" > <TextView android:layout_marginTop="15dp" android:id="@+id/friend_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textStyle="bold" android:textSize="20sp" android:text="姓名" /> <TextView android:layout_marginTop="10dp" android:id="@+id/friend_mode" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="18sp" android:text="动态" /> </LinearLayout > </LinearLayout > </RelativeLayout >
② 更换 LayoutManager
:
1 2 3 4 5 6 7 8 private void init () { GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(),4 ); this .setLayoutManager(gridLayoutManager); this .setAdapter(new MyAdapter(DataUtil.loadData(getContext()))); }
4. StaggeredGridLayoutManager
① 修改了item布局文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="10dp" > <LinearLayout android:id="@+id/main" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#009900" android:orientation="vertical" > <swu.xl.grid.XLImageView android:id="@+id/friend_icon" android:layout_width="100dp" android:layout_height="100dp" android:src="@drawable/ic_launcher_foreground" android:scaleType="fitXY" /> <LinearLayout android:layout_marginStart="20dp" android:layout_width="wrap_content" android:layout_height="0dp" android:orientation="vertical" android:layout_weight="1" > <TextView android:layout_marginTop="15dp" android:id="@+id/friend_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textStyle="bold" android:textSize="20sp" android:text="姓名" /> <TextView android:layout_marginTop="10dp" android:id="@+id/friend_mode" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="18sp" android:text="动态" /> </LinearLayout > </LinearLayout > </RelativeLayout >
② 更换 LayoutManager
:
1 2 3 4 5 6 7 8 private void init () { StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(4 ,StaggeredGridLayoutManager.VERTICAL); this .setLayoutManager(staggeredGridLayoutManager); this .setAdapter(new MyAdapter(DataUtil.loadData(getContext()))); }
四. 常用的属性 1 2 3 4 5 6 7 8 9 10 android:overScrollMode="never" android:scrollbars="none" android:focusable="true" android:focusableInTouchMode="true"
五. 问题解决 1. 瀑布流样式和网格样式的区别 瀑布流就是设置下几行或者几列,然后设定下方向而已。网格样式时不也一样是设置下几行或几列,也一样是要再设置个方向。那么为什么瀑布流不可以直接用网格样式来实现呢?它们两者有什么区别么?
下面以两者都设置为竖直方向多列的样式来区分:
1、网格样式每一行中的所有 item
高度是一致的,不同行可以不一样,但同行的都是一样的,因此它就实现不了瀑布流的样式了;瀑布流所有的 item
高度都允许不一样,所有能实现瀑布流样式。
2、网格样式支持 item
占据多列的宽度;瀑布流支持 item
占据总列数的宽度,不支持只占据其中几列。
3、当设置为水平方向样式时,以上结论中行列对调,宽度高度对调。
2. 使用RecyclerView的优点
提供 ViewHolder
模式,使得开发者真正操作的是 ViewHolder
,而不是像 ListView
中的 GridView
,需要开发者自己 setTag
和 view.getTag
。
同时支持列表布局和网格布局,而 ListView
只能支持列表布局,网格布局需要用 GridView
。
支持瀑布流布局。我们不在需要为实现瀑布流效果而苦恼。
操作动画。在对列表进行增加、删除时的动画。并且 Adapter
提供了增加删除某个 item
的方法。
性能与拓展性。RecyclerView
听起来像是回收的view,事实上, RecyclerView
本身就不关心 View
相关的显示、 View
显示什么内容( ViewHolder
来管理), View
怎么摆放( LayoutManager
来管理),也不关心动画( ItemAmator
来管理),甚至连分割线它都不管(由 ItemDecoration
来管理) 而它关心 View
的回收复用,这跟性能有关系。所以名字用 Recycle
也是有道理的。这样的好处是,把各个环节工作交付给了不同的类,类似“插件化”。特别方便拓展,自定义各种各样的差异化,而从这其中解耦出来。
3. 使用RecyclerView的缺点 需要自己实现 OnItemClickListener
点击事件。
参考文章 “大哥”已就位,赶紧来膜拜吧!—RecyclerView详解
RecyclerView