一. 前言 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