Kotlin_RecyclerView_上拉刷新2

RecyclerView 的上拉刷新加载更多的基本实现 参考上篇: https://blog.csdn.net/whjk20/article/details/106975642

上拉刷新还可以对RecyclerView 添加滑动监听 (addOnScrollListener), 然后通过回调进行模拟数据更新

这里主要把加载更多插到RecyclerView 最后, 并非RecyclerView的数据中。

目录

1.布局文件 (分开加载中和加载失败)

2. 数据类型(增加一个数据状态标志位)

3. 修改Adapter

3.修改Activity


1.布局文件 (分开加载中和加载失败)

此处省略,跟之前的差异不大,只是分成两个文件

2. 数据类型(增加一个数据状态标志位)

package com.example.androidrecyclerviewtest.data

class UserDataLoadMore {
    var userName: String
    var userImageId: Int
    var state: Int

    // state 在adpater 的getItemViewType中用到
    constructor(userNameId: String, userImageId: Int, state: Int) {
        this.userName = userNameId
        this.userImageId = userImageId
        this.state = state
    }
}

其中有三种状态:

    const val TYPE_NORMAL = 0
    const val TYPE_LOADING = 1
    const val TYPE_RELOAD = 2

3. 修改Adapter

class ListViewLoadMoreScrollAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder> {

    //方法2: 通过设置接口回调,则不需要持有具体类的引用
    private var loadMoreScrollActivity: ListViewLoadMoreScrollActivity
    private var datas: MutableList<UserDataLoadMore>

    constructor(loadMoreScrollActivity: ListViewLoadMoreScrollActivity, datas: MutableList<UserDataLoadMore>) {
        this.loadMoreScrollActivity = loadMoreScrollActivity
        this.datas = datas
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        var view: View
        return if (viewType == TYPE_LOADING) {
            view = View.inflate(parent.context, R.layout.item_loading, null)
            LoadingViewHolder(view)
        } else {
            if (viewType == TYPE_RELOAD) {
                view = View.inflate(parent.context, R.layout.item_reload, null)
                ReloadViewHolder(view)
            } else {
                view = View.inflate(parent.context, R.layout.item_list_view, null)
                NormalViewHolder(view)
            }
        }
    }

    //加一个,最后一个为加载中(并没有加到datas 里)
    override fun getItemCount(): Int {
        return if (datas != null) {
            //最后一个为reload, 则表示不需要加上 loading
            if (datas.size >= 1 && datas[datas.size - 1].state == TYPE_RELOAD) {
                datas.size
            } else {
                datas.size + 1
            }
        } else {
            0
        }
    }

    override fun getItemViewType(position: Int): Int {
        return if (position >= datas.size) {
            TYPE_LOADING
        } else {
            //TYPE_NORMAL
            datas[position].state
        }

        //return datas[position].state
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        if (holder is NormalViewHolder) {
            holder.setData(datas[position])
        }
    }

    class NormalViewHolder : RecyclerView.ViewHolder {
        private var image: ImageView
        private var nameText: TextView
        //private var state: Int = TYPE_NORMAL

        constructor(itemView: View) : super(itemView) {
            this.nameText = itemView.user_name
            this.image = itemView.user_image
        }

        fun setData(userData: UserDataLoadMore) {
            nameText.text = userData.userName
            image.setImageResource(userData.userImageId)
        }
    }

    class LoadingViewHolder : RecyclerView.ViewHolder {
        //private var state: Int = TYPE_LOADING

        constructor(itemView: View) : super(itemView) {

        }
    }

    inner class ReloadViewHolder : RecyclerView.ViewHolder {
        //private var state: Int = TYPE_LOADING

        constructor(itemView: View) : super(itemView) {
            itemView.retry.setOnClickListener {
                //先一处重新加载的(加载失败), 这里需要 size-1!!!
                datas.removeAt(datas.size - 1)
                loadMoreScrollActivity.randomAddDatas()
            }
        }
    }
}

3.修改Activity

class ListViewLoadMoreScrollActivity : AppCompatActivity() {
    private var datas = mutableListOf<UserDataLoadMore>()
    private lateinit var context: Context
    var random = Random(PIC_IDS.size)
    var isLoading = false
    lateinit var loadMoreScrollAdapter: ListViewLoadMoreScrollAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_load_more)
        context = this

        initDatas()
        loadMoreScrollAdapter = ListViewLoadMoreScrollAdapter(this, datas)
        showListView()
    }

    private fun initDatas() {
        datas.clear()
        addDatas(PIC_IDS.size)
    }

    private fun addDatas(addSize: Int) {
        if (addSize < 0) {
            return
        }
        // 模拟加载失败的情况,加载到最后一个(loading的并没有加到datas里),reload的也不应该加载到datas里的
        if (addSize == 0) {
            datas.add(UserDataLoadMore("失败了", PIC_IDS[0], TYPE_RELOAD))
           return
        }

        for (index in 0 until addSize) {
            var userData = UserDataLoadMore(
                context.resources.getString(USER_NAMES[index % PIC_IDS.size]),
                PIC_IDS[index % PIC_IDS.size],
                TYPE_NORMAL
            )
            datas.add(userData)
        }
    }

    private fun showListView() {
        //2. 创建并设置布局管理器
        var layoutManager = LinearLayoutManager(context)
        layoutManager.orientation = LinearLayoutManager.VERTICAL
        recycler_view.layoutManager = layoutManager


        // 3. 创建并设置adapter
        recycler_view.adapter = loadMoreScrollAdapter
        // 5. 上拉刷新


        recycler_view.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            // 如何防止一次滑动,多次调用导致的多次更新数据??? --> 判断 SCROLL_STATE_IDLE 才进行刷新
            // 还是会有重复刷新的情况 --> 延迟添加数据导致的,因此判断如果已经正在加载,则不再进行
            override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                var adapter = recyclerView.adapter
                var layoutManager = recyclerView.layoutManager

                if (layoutManager is LinearLayoutManager) {
                    adapter?.let {
                        if (layoutManager.findLastCompletelyVisibleItemPosition() == adapter.itemCount - 1
                            && newState == RecyclerView.SCROLL_STATE_IDLE
                            && !isLoading
                        ) {
                            var handler = Handler()
                            isLoading = true
   /*                         handler.postDelayed({
                                //随机添加数据 - random 每次都是从1开始,所以不能在这里定义random (也会有0的情况)
                                // 0的时候,判断为失败???
                                var newSize = random.nextInt(PIC_IDS.size)

                                Toast.makeText(context, "newSize = $newSize", Toast.LENGTH_SHORT)
                                    .show()
                                addDatas(newSize)
                                isLoading = false
                                adapter.notifyDataSetChanged()
                            }, 3000)*/
                            randomAddDatas()
                        }
                    }
                }
                super.onScrollStateChanged(recyclerView, newState)
            }
        })
    }

    fun randomAddDatas() {
        var handler = Handler()
        handler.postDelayed({
            //随机添加数据 - random 每次都是从1开始,所以不能在这里定义random (也会有0的情况)
            // 0的时候,判断为失败???
            var newSize = random.nextInt(PIC_IDS.size)

            Toast.makeText(context, "newSize = $newSize", Toast.LENGTH_SHORT)
                .show()
            addDatas(newSize)
            isLoading = false
            loadMoreScrollAdapter.notifyDataSetChanged()
        }, 3000)
    }
}

逻辑也很好理解,当滑动到最后一个条目时,进行模拟数据更新,并触发更新UI.

只是onScrollStateChanged 里面的状态要注意些,以防重复刷新

其实还是有很多问题的,只是为了学习上拉刷新的基本逻辑,后续再优化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值