简介
RecyclerView是什么?
- RecycleView是一个用于在有限的窗口中展示大量数据集的控件
- Google用于代替ListView的滑动组件
RecyclerView的优缺点
优点
由名字可知,RecyclerView,回收复用视图,RecyclerView只管回收与复用View,其他的你可以自己去设置,一个类实现一个功能,高度的解耦
缺点
RecyclerView实现控制点击、长按事件较为麻烦,需要自己写
详解
一、知识储备
RecylerView高度解耦,一个类实现一块功能,使用前需要先了解一下类
-
LayoutManager
布局管理器,默认提供LinearLayoutManager、GridLayoutManager、StaggeredGridLayoutManager三大类,分别可以实现ListView,GridView以及流式布局的列表效果。
-
Adapter
适配器,适配数据如何显示,通过实现RecyclerView.Adapter接口中的方法实现数据的适配。
同时,RecyclerView的适配器强制要求了我们必须要用Viewholder,让性能得到优化,而且getView方法不需自己写,我们只需要写好Viewholder,View的复用已经封装好了。
-
ItemDecoration
Decoration 的英文意思是装饰物的意思,引申到这里来,肯定也是与 RecyclerView 的界面装饰有关。我们常见的就是分割线和item间距的配置
-
SnapHelper
如果每个Item显示⼀屏、按⻚来显示,可以通过设置此类快速实现,有SnapHelper 、LinearSnapHelper 、PagerSnapHelper这三个类
-
itemAnimator
这个类可以实现item的增删动画,不想设置的话它的默认效果也挺好的。
二、使用步骤
RecyclerView的使用步骤大致是这样固定的,效果和性能在于细节
使用步骤:
1、创建RecyclerView 通常在xml中配置
2、代码中设置属性
确定布局样式 设置layoutManager
确定数据源
3、定义一个Adapter实现RecyclerView.Adapter接口中的方法
RecyclerView通过接口中的方法访问数据
a、创建一个类继承于 RecyclerView.ViewHolder,重复利用
b、重写adapter的接口方法
getItemCount:确定RecyclerView中有多少个item
onCreateViewHolder:确定每个item的具体视图
onBindViewHolder:绑定视图
4、设置item装饰器 addItemDecoration
1)系统提供的 DividerItemDecoration 分割线
2)⾃⼰创建⼀个类继承于ItemDecoration 重写onDraw或者onDrawOver、getItemOffset
- 如果每个Item显示⼀屏 按⻚来显示 SnapHelper 、LinearSnapHelper 、 PagerSnapHelper
三、使用案例
1、创建一个工程,在xml中加入RecyclerView控件(最新版RecyclerView在androidx包,老版本为v7包),本案例直接在activity_main.xml中加
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/mRecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
2、在MainActivity中获取RecyclerView控件,设置相关属性
由于AndroidStudio升级到4.1后,kotlin不默认使用id获取控件,而是建议用ViewBinding绑定控件,在此使用ViewBinding(即运行时为activity_main.xml生成一个ActivityMainBinding的类)
class MainActivity : AppCompatActivity() {
/** AS4.1版本不默认支持用id访问控件 这里使用ViewBinding
* 如果想要继续使用id访问控件 模块的build.gradle中加入 id 'kotlin-android-extensions'
* 这里默认生成了ActivityMainBinding的类,此类关联了activity_main.xml
*/
private var mBinding: ActivityMainBinding? = null
private val dataSource:ArrayList<Int> = ArrayList()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//绑定xml
mBinding = ActivityMainBinding.inflate(LayoutInflater.from(this))
//设置为xml的根容器 即ConstraintLayout
setContentView(mBinding?.root)
//设置布局样式
// mBinding?.mRecyclerView?.layoutManager = LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,false)
mBinding?.mRecyclerView?.layoutManager = StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL)
//确定数据源
for (i in 1..10){
if (i % 2 == 0){
dataSource.add(R.drawable.sy)
}else{
dataSource.add(R.drawable.gl)
}
}
//设置适配器
mBinding?.mRecyclerView?.adapter = MainAdapter(dataSource)
//辅助类 使得滑动如翻页
PagerSnapHelper().attachToRecyclerView(mBinding?.mRecyclerView)
//设置装饰decoration 间隔、分割线等
mBinding?.mRecyclerView?.addItemDecoration(MyItemDecoration())
}
}
3、创建item显示样式的xml
即用xml编写RecyclerView的每一个item显示需要的控件和布局,在adapter中进行解析和数据绑定
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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="wrap_content">
<ImageView
android:id="@+id/iconImageView"
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleType="fitCenter"
android:src="@drawable/desktop1"
app:layout_constraintDimensionRatio="16:9"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/titleTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="银河以北,吾彦最美"
android:textColor="#000"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/iconImageView" />
</androidx.constraintlayout.widget.ConstraintLayout>
4、创建一个类继承于RecyclerView.Adapter
通过实现其接口方法对RecyclerView进行适配,解释请看代码注释
class MainAdapter: RecyclerView.Adapter<MainAdapter.MyViewHold> {
lateinit var imageDataSource:ArrayList<Int>
constructor(images:ArrayList<Int>){
this.imageDataSource = images
}
//确定每个item的具体视图
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHold {
//获取xml的视图 xml-》View
//如果知道一个View 就可以通过这个view获取其上下文content
val layoutInflater = LayoutInflater.from(parent.context)
val itemView = layoutInflater.inflate(R.layout.main_recycler_item,parent,false)
// val itemView = layoutInflater.inflate(R.layout.card_item,parent,false)
return MyViewHold(itemView)
}
//视图解析出来之后 需不需要将数据绑定到上面
@SuppressLint("WrongConstant")
override fun onBindViewHolder(holder: MyViewHold, position: Int) {
holder.iconImageView.setImageResource(imageDataSource[position])
holder.titleView.text = if (position%2 ==0) "银河以北,吾彦最美" else "银河以南,为彦而燃"
//item点击事件
holder.iconImageView.setOnClickListener{
Toast.makeText(holder.iconImageView.context,holder.titleView.text,1000).show()
}
}
//确定RecyclerView中有多少个 Item
override fun getItemCount(): Int {
return imageDataSource.size
}
//传递来的view 是RecyclerView显示的每一个item
class MyViewHold: RecyclerView.ViewHolder{
lateinit var titleView:TextView
lateinit var iconImageView: ImageView
constructor(itemView:View):super(itemView){
titleView = itemView.findViewById(R.id.titleTextView)
iconImageView = itemView.findViewById(R.id.iconImageView)
}
}
}
5、设置itemDecoration
创建一个类继承于RecyclerView.ItemDecoration,设置间隔的话实现其getItemOffsets方法,再到MainActivity中设置recyclerView的itemDecoration
class MyItemDecoration: RecyclerView.ItemDecoration() {
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
outRect.set(10,10,10,10)
}
}
6、设置SnapHelper,翻页效果等
//辅助类 使得滑动如翻页
PagerSnapHelper().attachToRecyclerView(mBinding?.mRecyclerView)
7、设置点击事件
在onCreateViewHolder中设置
//确定每个item的具体视图
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHold {
//获取xml的视图 xml-》View
//如果知道一个View 就可以通过这个view获取其上下文content
val layoutInflater = LayoutInflater.from(parent.context)
val itemView = layoutInflater.inflate(R.layout.main_recycler_item,parent,false)
// val itemView = layoutInflater.inflate(R.layout.card_item,parent,false)
itemView.setOnClickListener{
//点击事件
}
return MyViewHold(itemView)
}
也可以在onBindViewHolder中对控件设置点击事件
//视图解析出来之后 需不需要将数据绑定到上面
@SuppressLint("WrongConstant")
override fun onBindViewHolder(holder: MyViewHold, position: Int) {
holder.iconImageView.setImageResource(imageDataSource[position])
holder.titleView.text = if (position%2 ==0) "银河以北,吾彦最美" else "银河以南,为彦而燃"
holder.iconImageView.setOnClickListener{
Toast.makeText(holder.iconImageView.context,holder.titleView.text,1000).show()
}
}