Android RecyclerView使用入门

1、RecyclerView关键类介绍

在Android开发中,只要有列表页,基本上就是RecyclerView。RecyclerView非常强大、非常灵活且非常重要。在RecyclerView出现之前其实已经有ListView和GridView等列表控件了。但是由于它们的使用相对复杂,对实现动画等各项定制难度较大,不利于实现业务需求,RecyclerView诞生了。

关于RecyclerView有以下几个关键的类:

  1. Adapter:适配器模式中的适配器,开发者需要自定义一个Adapter的子类并设置给RecyclerView。它主要负责ViewHolder的创建和数据的绑定。
  2. ViewHolder:顾名思义就是View的持有者。
  3. LayoutManager:布局管理器,负责列表项的测量、布局等操作。
  4. ItemDecoration:Item的装饰器,可以实现列表分割线等操作。
  5. RecyclerView:RecyclerView本身负责以上几个类的调度、滑动事件的处理等。

2、最简单的使用

RecyclerView的使用步骤:

  1. 获取RecyclerView,通过findViewById或者new的方式
  2. 创建Adapter类,并给RecyclerView设置Adapter实例
  3. 设置LayoutManager
  4. 设置ItemDecoration,可选
class SimplestActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val contentView = RecyclerView(this)

        // 必须设置LayoutManager
        contentView.layoutManager = LinearLayoutManager(this)
        // 必须设置Adapter
        contentView.adapter = TextAdapter()
        // ItemDecoration可以设置,也可以不设置,也可以设置多个
        contentView.addItemDecoration(DividerItemDecoration(this, RecyclerView.VERTICAL))

        setContentView(contentView, ViewGroup.LayoutParams(
            ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.MATCH_PARENT
        ))
    }

    private class TextAdapter: RecyclerView.Adapter<TextViewHolder>() {

        private val datas = ArrayList<String>()

        init {
            // 模拟数据
            for (i in 1 .. 100) {
                datas.add("Item $i")
            }
        }

        /**
         * 加载布局并创建ViewHolder
         */
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TextViewHolder {
            val inflater = LayoutInflater.from(parent.context)
            val itemView = inflater.inflate(android.R.layout.simple_list_item_1, parent, false)
            return TextViewHolder(itemView)
        }

        /**
         * 绑定数据
         */
        override fun onBindViewHolder(holder: TextViewHolder, position: Int) {
            holder.bind(datas[position])
        }

        override fun getItemCount() = datas.size
    }

    private class TextViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {

        var data: String? = null
        val textView = itemView as TextView

        init {
            itemView.setOnClickListener(this)
        }

        fun bind(data: String) {
            this.data = data
            textView.text = data
        }

        override fun onClick(v: View) {
            Toast.makeText(v.context, "$data was clicked", Toast.LENGTH_SHORT).show()
        }
    }

}

效果:

在这里插入图片描述

需要注意的是,必须给RecyclerView设置Adapter和LayoutManager,缺少前者,RecyclerView不知道该展示什么内容,缺少后者,RecyclerView不知道该怎么展示内容。这两者不设置的时候,我们会在Logcat中看到如下日志:

E/RecyclerView: No adapter attached; skipping layout

E/RecyclerView: No layout manager attached; skipping layout

接下来,展示一下网格布局的列表,只需要在以上代码的基础上稍作修改即可:

// 必须设置LayoutManager
contentView.layoutManager = GridLayoutManager(this, /*spanCount*/ 3)
// 必须设置Adapter
contentView.adapter = TextAdapter()
// ItemDecoration可以设置,也可以不设置,也可以设置多个
contentView.addItemDecoration(DividerItemDecoration(this, RecyclerView.VERTICAL))
contentView.addItemDecoration(DividerItemDecoration(this, RecyclerView.HORIZONTAL))

效果:

在这里插入图片描述

其中spanCount参数代表一行中有几个列。可以看到,我们只需要指定不同的LayoutManager就可以实现不同的布局样式了而不需要像以前一样把ListView替换成GridView。在实际业务开发中,我们可以根据主题设置动态地设置RecyclerView的LayoutManager实现线性列表和网格风格的切换。另外,如果Item本身在列表和网格的情况下的布局并不一样的情况下,可以针对两种情况实现不同的Adapter和ViewHolder。

除了LinearlayoutManager和GridLayoutManager外,Android还提供了一个StaggeredGridLayoutManager用于实现瀑布流布局。这里只展示代码中不同的部分:

class SimplestActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        
        ....
        // 必须设置LayoutManager
        contentView.layoutManager = StaggeredGridLayoutManager(3, RecyclerView.VERTICAL)
        // 必须设置Adapter
        contentView.adapter = TextAdapter()

        // 为了看得清楚,这里ItemDecoration设置成左右各有一部分空白
        contentView.addItemDecoration(object : RecyclerView.ItemDecoration() {
            override fun getItemOffsets(
                outRect: Rect,
                view: View,
                parent: RecyclerView,
                state: RecyclerView.State
            ) {
                outRect.left = 25
                outRect.right = 25
                outRect.top = 25
                outRect.bottom = 25
            }
        })

        ...
    }

    private class TextAdapter: RecyclerView.Adapter<TextViewHolder>() {

       ...

        /**
         * 加载布局并创建ViewHolder
         */
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TextViewHolder {
            val itemView = TextView(parent.context)
            itemView.gravity = Gravity.CENTER
            itemView.layoutParams = ViewGroup.LayoutParams(MATCH_PARENT, WRAP_CONTENT)
            return TextViewHolder(itemView)
        }

        ...
    }

    private class TextViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {

       ...

        fun bind(data: String) {
            this.data = data
            textView.text = data
            val layoutParams = itemView.layoutParams
            val even = adapterPosition % 2 == 0
            layoutParams.height = (if(even) 0 else 50) + 300
            itemView.layoutParams = layoutParams
            itemView.setBackgroundColor(Color.parseColor(if(even) "#FFAAAA" else "#AAFFFF"))
        }

        ...
    }

}

效果:
在这里插入图片描述

这三个LayoutManager都可以指定滚动的方向,不指定的话默认纵向滚动。

待续…

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值