Kotlin_RecyclerView_上拉刷新1

RecyclerView 的基本实现参考前篇:https://blog.csdn.net/whjk20/article/details/106950422

现实现 RecyclerView 的上拉刷新加载更多。

基本实现逻辑: 最后一条条目为加载更多, 有为两种状态,一是提示加载中, 二是加载失败提示重试。

目录

1.  增加 加载更多布局:

2. 定义数据类型

3.修改Adapter

4. Activity 注册刷新监听


1.  增加 加载更多布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">

    <androidx.cardview.widget.CardView
        app:cardUseCompatPadding="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <LinearLayout
                android:id="@+id/loading"
                android:orientation="horizontal"
                android:layout_width="match_parent"
                android:layout_height="90dp" >
                <ProgressBar
                    android:id="@+id/progress_bar"
                    android:layout_width="0dp"
                    android:layout_weight="1"
                    android:layout_height="match_parent"/>
                <TextView
                    android:layout_width="0dp"
                    android:layout_weight="1"
                    android:text="正在玩命的加载呢!!"
                    android:textSize="15sp"
                    android:gravity="center"
                    android:layout_height="match_parent"/>
            </LinearLayout>

            <TextView
                android:id="@+id/reload"
                android:text="加载失败,请重试"
                android:layout_width="match_parent"
                android:gravity="center"
                android:layout_height="90dp"/>

        </LinearLayout>

    </androidx.cardview.widget.CardView>

</RelativeLayout>

其中id:loading 为加载中,  id:reload表示加载失败请重试

2. 定义数据类型

其实和之前普通的数据类型一样,只是方便区分而已

class UserDataLoadMore {
    var userName: String
    var userImageId: Int

    constructor(userNameId: String, userImageId: Int, state: Int) {
        this.userName = userNameId
        this.userImageId = userImageId
    }
}

 

3.修改Adapter

直接上完整代码

class ListViewLoadMoreNormalAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private var onRefreshListener: OnRefreshListener ?=null
    private var datas: MutableList<UserDataLoadMore>

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

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        var view: View
        if (viewType == TYPE_LOAD_MORE) {
            view = View.inflate(parent.context, R.layout.item_load_more, null)
            return LoadMoreViewHolder(view)
        } else {
            view = View.inflate(parent.context, R.layout.item_list_view, null)
            return NormalViewHolder(view)
        }
    }

    override fun getItemCount(): Int {
        return if (datas != null) {
            datas.size
        } else {
            0
        }
    }

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

    override fun getItemViewType(position: Int): Int {
        return if (position == datas.size - 1) {
            TYPE_LOAD_MORE
        } else {
            TYPE_NORMAL
        }
    }

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

    inner class LoadMoreViewHolder : RecyclerView.ViewHolder {
        val LOAD_STATE_NORMAL = 0
        val LOAD_STATE_LOADING = 1
        val LOAD_STATE_RELOAD = 2
        private var loadingLayout: LinearLayout
        private var reloadLayout: TextView

        constructor(itemView: View) : super(itemView) {
            this.loadingLayout = itemView.loading
            this.reloadLayout = itemView.reload

            this.reloadLayout.setOnClickListener{
                update(LOAD_STATE_LOADING)
            }
        }

        fun update(state: Int){
            //初始化加载状态
            loadingLayout.visibility = View.GONE
            reloadLayout.visibility = View.GONE
            when(state) {
                LOAD_STATE_NORMAL -> {
                    loadingLayout.visibility = View.GONE
                    reloadLayout.visibility = View.GONE
                }
                LOAD_STATE_LOADING -> {
                    loadingLayout.visibility = View.VISIBLE
                    //还需要模拟数据加载
                    startLoadMore(this)
                }
                LOAD_STATE_RELOAD -> {
                    reloadLayout.visibility = View.VISIBLE
                    //此处需要响应点击事件
                }
            }
        }

        private fun startLoadMore(callBack: LoadMoreViewHolder) {
            onRefreshListener?.onUpPullOnRefresh(callBack)
        }
    }

    interface OnRefreshListener{
        fun onUpPullOnRefresh(callBack: LoadMoreViewHolder)
    }

    fun setOnRefreshListener(listener: OnRefreshListener) {
        this.onRefreshListener = listener
    }
}

其中,

(1) getItemViewType 获取条目类型时,最后一条条目设置为加载更多状态

(2) LoadMoreViewHolder 内部有三种状态,表示加载的过程,Normal 表示已经完成加载,Loading表示加载中,reload表示加载失败了。

内部update() 函数表示更新状态,并调整加载界面显示(visible)

(3) 创建时需要为加载失败控件增加点击监听,使其再进入加载中状态。

(4)在绑定ViewHolder时,更新状态为Loading, 然后通过回调模拟数据更新,Activity注册监听(setOnRefreshListener)并且实现该回调

即适配器 提供刷新接口、注册刷新接口、刷新回调

        private fun startLoadMore(callBack: LoadMoreViewHolder) {
            onRefreshListener?.onUpPullOnRefresh(callBack)
        }

4. Activity 注册刷新监听

    private fun initListener() {
        // 匿名内部类
        loadMoreNormalAdapter.setOnRefreshListener(object :
            ListViewLoadMoreNormalAdapter.OnRefreshListener {
            // 还需要持有adapter viewholder 的引用,才能模拟加载失败的状态
            override fun onUpPullOnRefresh(callBack: ListViewLoadMoreNormalAdapter.LoadMoreViewHolder) {
                randomAddDatas(callBack)
            }

        })
    }

(1) 其中randomAddDatas 表示模拟随机添加数据,然后更新UI,

(2)当新增随机数目为0时,则设置ViewHolder 状态为reload ,表示加载失败,则会更新最后一条条目状态为重新加载。

 

Activity 完整代码

class ListViewLoadMoreNormalActivity : AppCompatActivity() {
    private lateinit var loadMoreNormalAdapter: ListViewLoadMoreNormalAdapter
    private var datas = mutableListOf<UserDataLoadMore>()
    var random = Random(PIC_IDS.size)
    private lateinit var context: Context

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

        initDatas()
        loadMoreNormalAdapter =
            ListViewLoadMoreNormalAdapter(datas)
        initListener()
        showListView()
    }

    private fun initListener() {
        // 尝试使用懒惰表达代替 匿名内部类
        loadMoreNormalAdapter.setOnRefreshListener(object :
            ListViewLoadMoreNormalAdapter.OnRefreshListener {
            // 还需要持有adapter viewholder 的引用,才能模拟加载失败的状态
            override fun onUpPullOnRefresh(callBack: ListViewLoadMoreNormalAdapter.LoadMoreViewHolder) {
                randomAddDatas(callBack)
            }

        })
    }

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


        // 3. 创建并设置adapter
        recycler_view.adapter = loadMoreNormalAdapter
    }

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

    private fun addDatas(addSize: Int) {
        if (addSize < 0) {
            return
        }
        if (addSize == 0) {

        }

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

    fun randomAddDatas(callBack: ListViewLoadMoreNormalAdapter.LoadMoreViewHolder) {
        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()
            if (newSize == 0) {
                callBack.update(callBack.LOAD_STATE_RELOAD)
            } else {
                addDatas(newSize)
                loadMoreNormalAdapter.notifyDataSetChanged()
            }

        }, 3000)
    }
}

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

相对会复杂些。后续再总结

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值