Android基础之--RecyclerView实现多种Item布局

369 阅读3分钟

RecyclerView实现多种Item布局,如浏览器纵向的recyclerView会放不同类型的Item布局,效果图如下:

转存失败,建议直接上传图片文件

--------------本篇将以联系人界面为例来实现多种Item布局的RecyclerView--------------

  • RecyclerView实现多种Item布局

  1. 首先自行写一个Activity、RecyclerView布局和自定义Adapter,以及两个Item布局;
  2. 定义若干个ViewHolder,获取对应Item中的控件;
  3. 在自定义adapter中定义若干个常量作为多种Item布局的切换的入口;
  4. 重写RecyclerView的getItemViewType方法,根据返回的常量来标记对应的Item布局;
  5. 在Adapter重写的onCreateViewHolder方法中根据viewType类型绑定对应的Item布局,返回对应的ViewHolder;
  6. 在Adapter重写的onBindViewHolder方法中根据不同类型的holder绑定数据。

2. 定义ViewHolder

本示例实现两种不通类型的Item布局,因此需要自定义2个ViewHolder,在ViewHolder中根据Id去获取各自Item布局中的控件;

    class FirstViewHolder(view : View) : RecyclerView.ViewHolder(view){

        var contactImg1 : ImageView? = null
        var contactName1 : TextView? = null

        init{
            contactImg1 = view.findViewById(R.id.contact_item_img)
            contactName1 = view.findViewById(R.id.contact_item_name)
        }
    }

    class SecViewHolder(view : View) : RecyclerView.ViewHolder(view){

        var contactImg2 : ImageView? = null
        var contactName2 : TextView? = null

        init{
            contactImg2 = view.findViewById(R.id.contact_item_img_2)
            contactName2 = view.findViewById(R.id.contact_item_name_2)
        }
    }

3. 在自定义adapter中定义常量

这里定义常量主要是作为重写getItemViewType方法的判断条件,即哪种情况下显示哪种Item布局;

    val FIRST_ITEM : Int = 1
    val SEC_ITEM : Int = 2

4. 重写RecyclerView的getItemViewType方法

根据返回的常量来标记对应位置要显示的Item布局,如当添加Item的位置为3的倍数时使用第2种Item布局;

    override fun getItemViewType(position: Int): Int {
        if(position % 3 == 0){
            return SEC_ITEM
        }else{
            return FIRST_ITEM
        }
    }

5. onCreateViewHolder方法中根据viewType类型绑定对应的ViewHolder;

根据参数viewType可以得知当前position应该放置哪种类型的Item布局,如,当viewType为FIRST_ITEM时,绑定item1的布局返回,否则绑定item2的布局返回;

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {

        if(viewType == FIRST_ITEM){
            return FirstViewHolder(LayoutInflater.from(context).inflate(R.layout.addressbook_contact_item_1, parent, false))
        }else{
            return SecViewHolder(LayoutInflater.from(context).inflate(R.layout.addressbook_contact_item_2, parent, false))
        }

    }

6. onBindViewHolder方法中根据不同类型的holder绑定数据

  • kotlin语言写法:
    (1)首先需要调用getItemViewType方法获取当前位置的Item类型;
    (2)根据Item类型拿到对应ViewHolder,然后通过ViewHolder来更新对应类型Item中控件的数据显示;
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {

        var mContactItem = mContactList[position]
        val myViewType = getItemViewType(position)

        when(myViewType){
            FIRST_ITEM -> {
                holder as FirstViewHolder
                holder.contactImg1?.setImageResource(mContactItem.contactImgId)
                holder.contactName1?.text = mContactItem.contactName
            }
            SEC_ITEM -> {
                holder as SecViewHolder
                holder.contactImg2?.setImageResource(mContactItem.contactImgId)
                holder.contactName2?.text = mContactItem.contactName
            }
        }
    }

  • Java语言写法:
  1. Java的写法不需要调用getItemViewType方法来获取当前位置的Item类型,直接通过instanceof进行类型检查获取对应Item类型;
  2. 通过holder调Item中的控件之前,在holder实例前要写明是哪个ViewHolder类的实例。
        if(holder instanceof  FirstViewHolder) {
            ((FirstViewHolder)holder).contactName1?.setText(mContactItem.contactName);
        }else{
            ((SecViewHolder)holder).contactName2?.setText(mContactItem.contactName);
        }

---------------------自定义Adapter中的完整代码及效果图如下--------------------------

  • recyclerView实现多种Item布局的效果图

  • 完整代码
class AddressBookAdapter(val context : Context) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    private var mContactList = ArrayList<ContactItem>()
    val FIRST_ITEM : Int = 1
    val SEC_ITEM : Int = 2

    public fun setContactList(contactList : ArrayList<ContactItem>){

        this.mContactList = contactList
        notifyDataSetChanged()

    }

    class FirstViewHolder(view : View) : RecyclerView.ViewHolder(view){

        var contactImg1 : ImageView? = null
        var contactName1 : TextView? = null

        init{
            contactImg1 = view.findViewById(R.id.contact_item_img)
            contactName1 = view.findViewById(R.id.contact_item_name)
        }
    }

    class SecViewHolder(view : View) : RecyclerView.ViewHolder(view){

        var contactImg2 : ImageView? = null
        var contactName2 : TextView? = null

        init{
            contactImg2 = view.findViewById(R.id.contact_item_img_2)
            contactName2 = view.findViewById(R.id.contact_item_name_2)
        }
    }

    override fun getItemViewType(position: Int): Int {
        if(position % 3 == 0){
            return SEC_ITEM
        }else{
            return FIRST_ITEM
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {

        if(viewType == FIRST_ITEM){
            return FirstViewHolder(LayoutInflater.from(context).inflate(R.layout.addressbook_contact_item_1, parent, false))
        }else{
            return SecViewHolder(LayoutInflater.from(context).inflate(R.layout.addressbook_contact_item_2, parent, false))
        }

    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {

        var mContactItem = mContactList[position]
        val myViewType = getItemViewType(position)

        when(myViewType){
            FIRST_ITEM -> {
                holder as FirstViewHolder
                holder.contactImg1?.setImageResource(mContactItem.contactImgId)
                holder.contactName1?.text = mContactItem.contactName
            }
            SEC_ITEM -> {
                holder as SecViewHolder
                holder.contactImg2?.setImageResource(mContactItem.contactImgId)
                holder.contactName2?.text = mContactItem.contactName
            }
        }
    }

    override fun getItemCount(): Int  = mContactList.size

}

👀关注公众号:Android老皮!!!欢迎大家来找我探讨交流👀