RecyclerView使用攻略

简介

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

  1. 如果每个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()
        }
    }

四、运行结果

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342