前言
Hello 艾维巴蒂,今天给大家介绍一下 ListView
和 GridView
的“大哥“— RecyclerView
,这个控件是当下最流行且最常用的一个控件,并且在实战项目中它随处可见,而为什么将它称为“大哥”,请听我们娓娓道来~
简介
RecyclerView
是Google在API 21下 support.V7
包里的控件,用来替代 ListView
与 GridView
。官网对它的描述为:A flexible view for providing a limited window into a large data set。它是从Android5.0出现的全新列表组件,更加强大和灵活。
RecyclerView
的 support
包里默认提供了三个 LayoutManager
,分别是下列三个,可用于实现大部分场景的布局需求:线性布局、网格布局、瀑布流布局等等。
1、 LinearLayoutManager
现行管理器,支持横向、纵向。
2、 GridLayoutManager
网格布局管理器
3、 StaggeredGridLayoutManager
瀑布流式布局管理器
基本用法
1.引入依赖
代码语言:javascript复制implementation 'com.android.support:recyclerview-v7:27.1.1'
2.布局中添加RecyclerView
代码语言:javascript复制<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".recyclerview.RecyclerViewActivity">
<android.support.v7.widget.RecyclerView
android:id="@ id/rv_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white" />
</LinearLayout>
如果想去掉可滑动控件滑动到边缘的光晕效果,小伙伴们可以这样试试:
代码语言:javascript复制//在xml中设置
android:overScrollMode="never"
//在代码中设置
rvView.setOverScrollMode(View.OVER_SCROLL_NEVER);
3.Adapter适配器设置
在使用的时候更新需要使用 Adapter
适配器。但是 RecyclerView
使用的适配器并不是之前的 BaseAdapter
了。RecyclerView
使用的适配器需要继承 RecyclerView.Adapter<RecyclerViewAdapter.MyViewHolder>
。这里 <>
可能有些小白不知道是什么意思,大概说一下, <>
这个是泛型,在箭括号里可以写自己定义好的适配器,因为而RecyclerView.ViewHolder本身是一个抽象类,我们往往自己继承这个抽象类,然后绑定我们的布局控件对象。继承该类时必须传入一个itemView,表示这个item显示的View,我这里自定义的适配器命名为MyViewHolder。
在Adapter中必须实现的三个方法:
a、//列表页需要知道有多少个条目publicintgetItemCount()
b、//创建一个ViewHolder,我们可以根据viewType的不同而创建不同的ViewHolder实现列表页各种不一样的itempublicRecyclerView.ViewHolderonCreateViewHolder(@NonNullViewGroupparent,intviewType)
c、//在ViewHolder中绑定数据publicvoidonBindViewHolder(@NonNullRecyclerView.ViewHolderholder,intposition)
这里我写了一个简单的聊天列表样式,并且对头像添加了点击事件
代码语言:javascript复制public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.MyViewHolder> {
private Context mContext;
private List<String> mList = new ArrayList<String>();
private RecyclerViewAdapter.OnItemChatClickLitener mOnItemClickLitener;
public RecyclerViewAdapter(Context context, RecyclerViewAdapter.OnItemChatClickLitener mLitener) {
this.mContext = context;
this.mOnItemClickLitener = mLitener;
}
public List<String> getData() {
return mList;
}
@Override
public RecyclerViewAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = View.inflate(mContext, R.layout.adapter_recyclerview_layout, null);
return new RecyclerViewAdapter.MyViewHolder(view);
}
@Override
public void onBindViewHolder(final RecyclerViewAdapter.MyViewHolder holder, final int position) {
final String str = mList.get(position);
//判断String传值是否为空
if (!TextUtils.isEmpty(str)) {
//给姓名赋值
holder.tvName.setText(str);
//头像设置点击事件
holder.ivHeadPortrait.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mOnItemClickLitener != null) {
mOnItemClickLitener.onItemClick(position);
}
}
});
}
}
@Override
public int getItemCount() {
return mList.size();
}
public interface OnItemChatClickLitener {
void onItemClick(int position);
}
/**
* 新建一个适配器类,同时内部新建一个ViewHolder类并继承相相应的类
*/
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView tvName;
ImageView ivHeadPortrait;
public MyViewHolder(View itemView) {
// 这里很重要,参数中的View对象也很重要
super(itemView);
ivHeadPortrait = itemView.findViewById(R.id.iv_headportrait);
tvName = itemView.findViewById(R.id.tv_name);
}
}
}
item
的布局 R.layout.adapter_recyclerview_layout
代码如下:
<?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:background="@color/white"
android:paddingLeft="10dp"
android:paddingRight="10dp">
<ImageView
android:id="@ id/iv_headportrait"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginTop="10dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="10dp"
android:src="@mipmap/moren_icon" />
<TextView
android:id="@ id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:layout_toRightOf="@id/iv_headportrait"
android:text="小红"
android:textColor="@color/black"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@id/iv_headportrait"
android:layout_toRightOf="@id/iv_headportrait"
android:text="你领取了谁的红包"
android:textColor="@color/color_9A9A9A"
android:textSize="14sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginTop="15dp"
android:text="7分钟前"
android:textColor="@color/color_9A9A9A"
android:textSize="13sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_below="@id/iv_headportrait"
android:background="@color/color_9A9A9A" />
</RelativeLayout>
4.在activity中初始化RecyclerView,并配置具体用法已在代码中标注,如下:
代码语言:javascript复制public class RecyclerViewActivity extends AppCompatActivity {
private List<String> mList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recyclerview);
RecyclerView rvView = (RecyclerView) findViewById(R.id.rv_view);
RecyclerViewAdapter rvAdapter = new RecyclerViewAdapter(this, new RecyclerViewAdapter.OnItemChatClickLitener() {
@Override
public void onItemClick(int position) {
//对头像添加了点击事件
Toast.makeText(RecyclerViewActivity.this, "点击了:" mList.get(position), Toast.LENGTH_SHORT).show();
}
});
//LinearLayoutManager是用来做列表布局,也就是单列的列表
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
//设置为垂直布局,默认是垂直的(垂直:LinearLayoutManager.VERTICAL,水平:LinearLayoutManager.HORIZONTAL)
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
//设置布局管理器
rvView.setLayoutManager(linearLayoutManager);
//对RecyclerView设置Adapter
rvView.setAdapter(rvAdapter);
//给列表初始化数据
setListData();
rvAdapter.getData().addAll(mList);
rvAdapter.notifyDataSetChanged();
}
/**
* 给列表初始化数据
*/
private void setListData() {
mList = new ArrayList<String>();
mList.add("小红");
mList.add("imageview");
mList.add("小蓝");
mList.add("小绿");
mList.add("小明");
mList.add("TextView");
mList.add("小花");
mList.add("嘿嘿");
mList.add("是你呀");
mList.add("editview");
mList.add("listview");
mList.add("gridview");
mList.add("ConstraintLayout");
mList.add("Service");
mList.add("Activity");
mList.add("RelativeLayout");
mList.add("嗯嗯");
mList.add("小粉");
}
}
代码语言:javascript复制**步骤:**
**1.获取RecyclerView对象 。**
**2.初始化数据 。**
**3.适配器实例化 。**
**4.设置LayoutManager**
**5.设置Adapter 。**
注意敲黑板了:
rvView.setLayoutManager(linearLayoutManager);
要给recyclerview设置布局管理器,否则不显示内容
具体效果如下:
水平RecyclerView:
代码语言:javascript复制//LinearLayoutManager是用来做列表布局,也就是单列的列表
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
//设置为垂直布局,默认是垂直的(垂直:LinearLayoutManager.VERTICAL,水平:LinearLayoutManager.HORIZONTAL)
linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
//设置布局管理器
rvView.setLayoutManager(linearLayoutManager);
这里我们换一个布局样式:R.layout.adapter_rv_horizontal_layout
<?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:background="@color/white"
android:paddingLeft="10dp"
android:paddingRight="10dp">
<ImageView
android:id="@ id/iv_headportrait"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="10dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="10dp"
android:src="@mipmap/moren_icon" />
<TextView
android:id="@ id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/iv_headportrait"
android:layout_centerHorizontal="true"
android:gravity="center_horizontal"
android:text="小红"
android:textColor="@color/black"
android:textSize="14sp"
android:textStyle="bold" />
</RelativeLayout>
具体效果如下:
上面我们已经初步体验了下 LinearLayoutManager
,接下来看 GridLayoutManager
。
设置网格布局GridLayoutManager
日常开发经常需要有多行或多列的形式来展示各个卡位信息,而一些类似于九宫格之类的布局也可以用这个实现。只需要修改设置布局管理器即可,还是很nice的。
代码语言:javascript复制//设置网格布局
GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 4);
//设置布局管理器
rvView.setLayoutManager(gridLayoutManager);
效果如下:
*设置竖直瀑布流布局StaggeredGridLayoutManager *
这里同样还是修改设置布局管理器即可,秒秒钟的事情
:
代码语言:javascript复制//设置竖直瀑布流布局
StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(4, StaggeredGridLayoutManager.VERTICAL);
//设置布局管理器
rvView.setLayoutManager(staggeredGridLayoutManager);
效果如下:
瀑布流样式和网格样式的区别
也许有人会疑惑,瀑布流就是设置下几行或者几列,然后设定下方向而已。网格样式时不也一样是设置下几行或几列,也一样是要再设置个方向。那么为什么瀑布流不可以直接用网格样式来实现呢?它们两者有什么区别么?
有去尝试过的就清楚了,这是两种完全不一样的布局样式。下面以两者都设置为竖直方向多列的样式来区分:
1、网格样式每一行中的所有 item
高度是一致的,不同行可以不一样,但同行的都是一样的,因此它就实现不了瀑布流的样式了;瀑布流所有的 item
高度都允许不一样,所有能实现瀑布流样式。
2、网格样式支持 item
占据多列的宽度;瀑布流支持 item
占据总列数的宽度,不支持只占据其中几列。
3、当设置为水平方向样式时,以上结论中行列对调,宽度高度对调。
使用RecyclerView的优缺点
优点:
1、提供 ViewHolder
模式,使得开发者真正操作的是 ViewHolder
,而不是像 ListView
中的 GridView
,需要开发者自己 setTag
和 view.getTag
。
2、同时支持列表布局和网格布局,而 ListView
只能支持列表布局,网格布局需要用 GridView
。
3、支持瀑布流布局。我们不在需要为实现瀑布流效果而苦恼
4、操作动画。在对列表进行增加、删除时的动画。并且 Adapter
提供了增加删除某个 item
的方法
5、性能与拓展性。RecyclerView
听起来像是回收的view,事实上, RecyclerView
本身就不关心 View
相关的显示、 View
显示什么内容( ViewHolder
来管理), View
怎么摆放( LayoutManager
来管理),也不关心动画( ItemAmator
来管理),甚至连分割线它都不管(由 ItemDecoration
来管理) 而它关心 View
的回收复用,这跟性能有关系。所以名字用 Recycle
也是有道理的。这样的好处是,把各个环节工作交付给了不同的类,类似“插件化”。特别方便拓展,自定义各种各样的差异化,而从这其中解耦出来
缺点:需要自己实现 OnItemClickListener
点击事件(这么实用的需求,Google竟然让我们自己实现...,不过还好我们自己写)
结语
本篇完,如果你觉得本篇对你有所帮助,欢迎转载分享,标志出处即可,谢谢支持。