目录
前言
1. 基本使用
1.1 依赖
1.2 展示列表
1.2.1 编写布局文件
1.2.2 编写Adapter
1.2.3 编写ViewHolder
1.2.4 RecyclerView设置
1.2.5 效果图
2. 多类型列表
2.1 思路
2.2 编码
2.2.1 新增子项布局
2.2.2 新增ViewHolder
2.2.3 重写getItemViewType
2.2.4 修改后的Adapter
2.2.5 实现效果
3. LayoutManager
4. ItemDecoration
5. SnapHelper
6. ItemTouchHelper
7. Scrollview 嵌套
文章属于学习总结,因为在学习Koltin,所以本文代码使用的是Kotlin语言。
网上充满了类似的文章,但为什么还要写这篇文章呢,主要是想自己把RecyclerView相关的知识点梳理一下,然后自己写一下记忆才深刻一些。
另外强烈建议查看鸿洋大神的文章:Android RecyclerView 使用完全解析 体验艺术般的控件
dependencies {
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:recyclerview-v7:28.0.0'
}
现在要实现的是展示一个图片列表,需要进行如下步骤:
自定义Adapter继承RecyclerView.Adapter,且必须重写三个方法,另外还需把需要展示的列表数据传入Adapter中
class ImageRecycleAdapter : RecyclerView.Adapter() {
//需要展示的图片列表数据
var imageResources: List = ArrayList()
set(value) {
field = value
//数据已改变,通知RecyclerView刷新
notifyDataSetChanged()
}
// 创建一个承载子项视图的ViewHolder
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
TODO("not implemented")
}
//返回列表子项长度
override fun getItemCount(): Int = imageResources.size
//将指定位置的数据与视图绑定
override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, position: Int) {
TODO("not implemented")
}
}
RecyclerView.Adapter 必需一个ViewHolder来承载子项View,同时也就是说还需要一个子项View,布局如下:
以上布局展示的效果为:图片宽充满屏幕,高为宽的2/3,如果还不熟悉 ConstraintLayout 的,可以学习下,很不错布局。
自定义ViewHolder,继承于RecyclerView.ViewHolder
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
//将数据与View绑定
fun bindView(@DrawableRes imageResource : Int){
/**
* 为什么没使用FindViewById呢?
* 因为 import kotlinx.android.synthetic.main.recycle_item_image.view.*
* 创建Android Kotlin 工程会自动引入扩展插件 apply plugin: 'kotlin-android-extensions'
* 详情可查看:https://www.kotlincn.net/docs/tutorials/android-plugin.html
*/
itemView.imageView.setImageResource(imageResource)
}
}
然后替换Adapter中的RecyclerView.ViewHolder为自定义的ViewHolder,完整的Adapter + ViewHolder 代码如下
package cn.xhuww.recyclerview.adapter
import android.support.annotation.DrawableRes
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import cn.xhuww.recyclerview.R
import kotlinx.android.synthetic.main.recycle_item_image.view.*
class ImageRecycleAdapter : RecyclerView.Adapter() {
//需要展示的图片列表数据
var imageResources: List = ArrayList()
set(value) {
field = value
//数据已改变,通知RecyclerView刷新
notifyDataSetChanged()
}
// 创建一个承载子项视图的ViewHolder
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ImageRecycleAdapter.ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.recycle_item_image, parent, false)
return ViewHolder(view)
}
//返回列表子项长度
override fun getItemCount(): Int = imageResources.size
//将指定位置的数据与视图绑定
override fun onBindViewHolder(viewHolder: ImageRecycleAdapter.ViewHolder, position: Int) {
viewHolder.bindView(imageResources[position])
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
//将数据与View绑定
fun bindView(@DrawableRes imageResource: Int) {
itemView.imageView.setImageResource(imageResource)
}
}
}
package cn.xhuww.recyclerview.layoutmanager
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.DividerItemDecoration
import android.support.v7.widget.LinearLayoutManager
import cn.xhuww.recyclerview.R
import cn.xhuww.recyclerview.adapter.ImageRecycleAdapter
import kotlinx.android.synthetic.main.activity_recycle_view.*
class RecyclerViewActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_recycle_view)
//添加10张图片
val imageList = ArrayList()
for (i in 0 until 10) {
imageList.add(R.mipmap.image)
}
val imageAdapter = ImageRecycleAdapter().apply {
imageResources = imageList
}
val linearLayoutManager = LinearLayoutManager(this)
//添加分割线
val itemDecoration = DividerItemDecoration(this, DividerItemDecoration.VERTICAL)
recyclerView.apply {
layoutManager = linearLayoutManager
adapter = imageAdapter
addItemDecoration(itemDecoration)
}
}
}
很多时候我们需要在一个列表下展示不同式样的View,如下图所示
多类型列表展示可采用RecyclerView 提供的两个方法来实现
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
TODO("not implemented")
}
override fun getItemViewType(position: Int): Int {
return super.getItemViewType(position)
}
通过 getItemViewType方法传入不同的 ViewType,然后 onCreateViewHolder 根据不同的ViewType 创建不同的ViewHolder,
然后在根据不同的ViewHolder类型,进行 onBindViewHolder
新建 recycle_item_text_image.xml ,为了方便,只是变更文本内容。
class TextImageViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bindView(titleStr: String) {
itemView.titleTextView.text = titleStr
}
}
override fun getItemViewType(position: Int): Int {
val data = items[position]
//如果数据是 Int 则只展示图片,如果是String 则展示 文本+图片
return when (data) {
is Int -> VIEW_TYPE_IMAGE
else -> VIEW_TYPE_TEXT_IMAGE
}
}
此处是根据数据类型的不同,展示不同的视图,也可以采用 根据位置的不同展示不同的视图,例如添加 Header 以及 Footer
override fun getItemViewType(position: Int): Int {
return when (position) {
0 -> 0//Header
itemCount - 1 -> 1 //Footer
else -> 2 //Normal
}
}
package cn.xhuww.recyclerview.adapter
import android.support.annotation.DrawableRes
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import cn.xhuww.recyclerview.R
import kotlinx.android.synthetic.main.recycle_item_image.view.*
import kotlinx.android.synthetic.main.recycle_item_text_image.view.*
class ImageRecycleAdapter : RecyclerView.Adapter() {
//需要展示的图片列表数据
var items: List = ArrayList()
set(value) {
field = value
//数据已改变,通知RecyclerView刷新
notifyDataSetChanged()
}
// 创建一个承载子项视图的ViewHolder
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
return when (viewType) {
VIEW_TYPE_IMAGE ->
ViewHolder(inflater.inflate(R.layout.recycle_item_image, parent, false))
else ->
TextImageViewHolder(inflater.inflate(R.layout.recycle_item_text_image, parent, false))
}
}
//返回列表子项长度
override fun getItemCount(): Int = items.size
//将指定位置的数据与视图绑定
override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, position: Int) {
val data = items[position]
when (viewHolder) {
is ViewHolder ->
if (data is Int) viewHolder.bindView(data)
is TextImageViewHolder ->
if (data is String) viewHolder.bindView(data)
}
}
override fun getItemViewType(position: Int): Int {
val data = items[position]
//如果数据是 Int 则只展示图片,如果是String 则展示 文本+图片
return when (data) {
is Int -> VIEW_TYPE_IMAGE
else -> VIEW_TYPE_TEXT_IMAGE
}
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
//将数据与View绑定
fun bindView(@DrawableRes imageResource: Int) {
itemView.imageView.setImageResource(imageResource)
}
}
class TextImageViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bindView(titleStr: String) {
itemView.titleTextView.text = titleStr
}
}
companion object {
const val VIEW_TYPE_IMAGE = 1
const val VIEW_TYPE_TEXT_IMAGE = 2
}
}
在1.2.4 Activity的基础上,将模拟数据修改一下即可,实现效果。
class RecyclerViewActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
......
val dataList = ArrayList()
for (i in 0 until 10) {
if (i % 3 == 0)
dataList.add(R.mipmap.image)
else
dataList.add(resources.getString(R.string.positive_content))
}
val imageAdapter = ImageRecycleAdapter().apply {
items = dataList
}
......
}
}
文章链接:Android控件RecyclerView(二)——LayoutManager及其自定义
文章链接:Android控件RecyclerView(三)——ItemDecoration的使用与自定义
文章链接:Android控件RecyclerView(四)——SnapHelper搭配自定义LayoutManager实现无限循环滑动Banner