Android控件RecyclerView(一)——大家都知道的RecyclerView

目录

前言

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 使用完全解析 体验艺术般的控件

1. 基本使用

1.1 依赖

dependencies {
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support:recyclerview-v7:28.0.0'
}

1.2 展示列表

现在要实现的是展示一个图片列表,需要进行如下步骤:

  1. 编写布局文件
  2. 编写Adapter
  3. 编写ViewHolder
  4. RecyclerView 设置Adapter以及LayoutManager 以及添加分割线  ItemDecoration

1.2.1 编写布局文件

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
</android.support.constraint.ConstraintLayout>

1.2.2 编写Adapter

自定义Adapter继承RecyclerView.Adapter,且必须重写三个方法,另外还需把需要展示的列表数据传入Adapter中

class ImageRecycleAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
    //需要展示的图片列表数据
    var imageResources: List<Int> = 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")
    }
}

1.2.3 编写ViewHolder

RecyclerView.Adapter 必需一个ViewHolder来承载子项View,同时也就是说还需要一个子项View,布局如下:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:scaleType="fitXY"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintDimensionRatio="3:2"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

以上布局展示的效果为:图片宽充满屏幕,高为宽的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<ImageRecycleAdapter.ViewHolder>() {
    //需要展示的图片列表数据
    var imageResources: List<Int> = 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)
        }
    }
}

1.2.4 RecyclerView设置

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<Int>()
        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)
        }
    }
}

1.2.5 效果图

2. 多类型列表

很多时候我们需要在一个列表下展示不同式样的View,如下图所示

 2.1 思路

多类型列表展示可采用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

2.2 编码

2.2.1 新增子项布局  

新建 recycle_item_text_image.xml ,为了方便,只是变更文本内容。

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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">

    <TextView
        android:id="@+id/titleTextView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginTop="16dp"
        android:layout_marginBottom="16dp"
        android:textSize="15sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/imageView_normal"
        app:layout_constraintHorizontal_weight="5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="你的名字" />

    <ImageView
        android:id="@+id/imageView_normal"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="16dp"
        android:layout_marginBottom="16dp"
        android:scaleType="fitXY"
        android:src="@mipmap/image_positive"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintDimensionRatio="3:2"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_weight="3"
        app:layout_constraintStart_toEndOf="@+id/titleTextView"
        app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

2.2.2 新增ViewHolder

    class TextImageViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        fun bindView(titleStr: String) {
            itemView.titleTextView.text = titleStr
        }
    }

 2.2.3 重写getItemViewType

    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
        }
    }

2.2.4 修改后的Adapter

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<RecyclerView.ViewHolder>() {
    //需要展示的图片列表数据
    var items: List<Any> = 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
    }
}

2.2.5 实现效果

在1.2.4 Activity的基础上,将模拟数据修改一下即可,实现效果。

class RecyclerViewActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        ......

        val dataList = ArrayList<Any>()
        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
        }
 
        ......
    }
}

3. LayoutManager

文章链接:Android控件RecyclerView(二)——LayoutManager及其自定义

4. ItemDecoration 

文章链接:Android控件RecyclerView(三)——ItemDecoration的使用与自定义

5. SnapHelper

文章链接:Android控件RecyclerView(四)——SnapHelper搭配自定义LayoutManager实现无限循环滑动Banner

6. ItemTouchHelper

7. Scrollview 嵌套

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值