RecyclerView实现包含倒计时的列表

功能:

1.包含计时器的 RecyclerView 列表

2.支持刷新和加载更多(分页加载)

效果图:

 

实现思路:

内部维护一个 map, key 为 adapter 绑定数据模型的唯一 id, value 为绑定的数据模型,

map 保存需要更新倒计时的 model,

启动一个定时器, 每个间隔周期遍历一次 map, 取出 map 中数据, 更新 model 的倒计时属性, 最后局部更新 item.

主要代码 adapter :

package com.example.recyclertimerdemo

import android.util.ArrayMap
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import java.util.*
import java.util.concurrent.TimeUnit


private const val COUNT_DOWN_TIME = 30

/**
 * @Author: qqyang
 * @Date: 2022/6/8
 * @Description:
 * <p>
 *  内部维护一个 map, key 为 adapter 绑定数据模型的唯一 id, value 为绑定的数据模型,
 *  map 保存需要更新倒计时的 model,
 *  启动一个定时器, 每个间隔周期遍历一次 map, 取出 map 中数据, 更新 model 的倒计时属性, 最后局部更新 item.
 *  注意: 不要忘记界面销毁时调用 [release] 释放资源.
 * </p>
 */
class UserAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    /**
     * rxjava 实现倒计时.
     */
    private var mTimerSubscribe: Disposable? = null

    private val mList: MutableList<User> by lazy { LinkedList() }

    /**
     * 用来存储当前正在进行倒计时的 user.
     */
    private val mUserMap by lazy { ArrayMap<Int, User>() }


    fun clearData() {
        mList.clear()
        notifyDataSetChanged()
    }

    fun addDataList(dataList: List<User>) {
        mList.addAll(dataList)
        notifyDataSetChanged()
    }

    fun release() {
        mTimerSubscribe?.dispose()
        mTimerSubscribe = null
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return UserViewHolder(
            LayoutInflater.from(parent.context).inflate(R.layout.adapter_user, parent, false)
        )
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        val user = mList[position]
        user.itemPosition = position // 设置 item position.
        val vh = holder as UserViewHolder
        vh.tvName.text = user.name
        if (user.isRunning()) {
            disableCountDown(vh.btnCountDown)
            holder.btnCountDown.text = "倒计时: ${user.countDownTime}S"
            startTimer(user)
        } else {
            enableCountDown(vh.btnCountDown)
        }
        vh.btnCountDown.setOnClickListener {
            user.countDownTime = COUNT_DOWN_TIME
            holder.btnCountDown.text = "倒计时: ${user.countDownTime}S"
            startTimer(user)
        }
    }

    /**
     * 局部更新倒计时 view.
     */
    override fun onBindViewHolder(
        holder: RecyclerView.ViewHolder, position: Int, payloads: MutableList<Any>
    ) {
        if (payloads.isEmpty()) {
            super.onBindViewHolder(holder, position, payloads)
        } else {
            val user = payloads[0]
            if (user is User && holder is UserViewHolder) {
                if (user.isRunning()) {
                    // 如果正在进行倒计时, 禁止重复点击.
                    disableCountDown(holder.btnCountDown)
                    holder.btnCountDown.text = "倒计时: ${user.countDownTime}S"
                } else {
                    enableCountDown(holder.btnCountDown)
                }
            }
        }
    }

    override fun getItemCount() = mList.size

    private fun enableCountDown(btn: Button) {
        btn.isClickable = true
        btn.text = "开始倒计时"
    }

    private fun disableCountDown(btn: Button) {
        btn.isClickable = false
    }

    /**
     * view holder.
     */
    internal class UserViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val tvName: TextView by lazy { itemView.findViewById(R.id.tvName) }
        val btnCountDown: Button by lazy { itemView.findViewById(R.id.btnCountDown) }
    }

    /**
     * 启动计时器.
     */
    private fun startTimer(user: User) {
        mUserMap[user.id] = user
        if (null == mTimerSubscribe) {
            // 间隔 1s.
            mTimerSubscribe = Observable.interval(1, TimeUnit.SECONDS)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe {
                    val iterator = mUserMap.entries.iterator()
                    while (iterator.hasNext()) {
                        val bean = iterator.next().value
                        bean.countDownTime -= 1
                        if (bean.countDownTime <= 0) { // 倒计时结束, 从列表移除数据.
                            iterator.remove()
                        }
                        considerNotifyItemChanged(bean)
                    }
                }
        }
    }

    /**
     * 考虑是否更新列表.
     * 如果需要更新的数据已经不在列表中(ex: 进行了刷新操作, 刷新后, 接口返回的新数据列表中没有当前需要进行刷新倒计时的数据), 不进行更新.
     */
    private fun considerNotifyItemChanged(user: User) {
        mList.firstOrNull { it.id == user.id }?.let {
            notifyItemChanged(user.itemPosition, user)
        }
    }

}

全部代码地址:

https://github.com/QQQQQQY/RecyclerViewTimerListDemo

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值