旧机宝开发笔记之:自定义刷新控件(兼RecyclerView)的使用

之前定义的刷新控件在使用的时候,基本等同于RecyclerView的使用,对于刷新操作只是增加了一个加载数据的回调罢了,因而本篇说是之前刷新控件的使用,大部分内容还是RecyclerView的使用。
旧机宝的“设备页”打算分为三种布局,从上到下依次是一个查询bar,一个轮播的banner,还有每行两列的设备列表。
在这里插入图片描述

第一步:在布局中使用自定义刷新控件

<wang.buxiang.wheel.widget.refresh.RefreshLayout
        android:id="@+id/refreshLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </wang.buxiang.wheel.widget.refresh.RefreshLayout>

第二步:继承之前的自定义Adapter,实现数据适配

首页共有三种布局,搜索框、轮播横幅、设备项,至于最后的一项“没有更多数据”则是封装的刷新控件自动添加的,并不需要我们关心。

enum class ViewType{
        SEARCH,BANNER,DEVICE
    }

对于搜索框可以就是一个图片,而Banner则需要通过一个ViewPager来实现,之前说过viewpager的fragment专用adapter,这次则是用到更普适的PagerAdapter。首先是保存数据的变量们

private var phoneDevices=ArrayList<PhoneDevice>()
    private var banners= ArrayList<Int>()
    internal var bannerViewPager: ViewPager? = null

banner中的数据是保存在本地的,直接在init中添加数据。

 init {
        banners.add(R.drawable.ic_banner_how_to_use)
        banners.add(R.drawable.ic_banner_need)
        banners.add(R.drawable.ic_banner_feedback)
    }

定义更新adapter数据的方法,主要是存在变动的“设备项”,下拉刷脸的回调会用到setData方法,重置数据。而上划加载更多则用到addData方法,用于在现有数据基础之上添加数据。notifyDataSetChanged()则是要求adapter更新数据。

fun setData(phoneDeviceList: ArrayList<PhoneDevice>) {
        phoneDevices = phoneDeviceList
        notifyDataSetChanged()
    }

    fun addData(phoneDeviceList: ArrayList<PhoneDevice>) {
        phoneDevices .addAll(phoneDeviceList)
        notifyDataSetChanged()
    }

定义三个内部类,继承ViewHolder,这是recyclerview特有的机制,用于提高性能。这三个用于hold每个item布局的控件们。

internal inner class DeviceViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        var img_icon: ImageView = itemView.findViewById(R.id.img_icon)
        var tv_name: TextView = itemView.findViewById(R.id.tv_name)
        var bt_init: Button = itemView.findViewById(R.id.bt_choose)
    }

    internal inner class SearchViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        var tv_serach: TextView = itemView.findViewById(R.id.tv_search)

    }

    internal inner class BannerViewHoler(itemView: View) : RecyclerView.ViewHolder(itemView) {
        var viewPager: ViewPager = itemView.findViewById(R.id.viewPager)
    }

根据位置不同,返回不同的viewtype,这里第一行是搜索框,第二行是banner,剩下的都是设备项。

override fun myGetItemViewType(position: Int): Int {
        return when(position){
            0-> ViewType.SEARCH.ordinal
            1->ViewType.BANNER.ordinal
            else ->ViewType.DEVICE.ordinal
        }
    }

根据viewtype的不同,用各自的布局创建各自的viewholder并返回

override fun myOnCreateViewHolder(viewGroup: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return when(viewType){
            ViewType.SEARCH.ordinal-> SearchViewHolder(LayoutInflater.from(viewGroup.context).inflate(R.layout.item_function_search, null))
            ViewType.BANNER.ordinal->BannerViewHoler(LayoutInflater.from(viewGroup.context).inflate(R.layout.item_function_banner, null))
            else-> DeviceViewHolder(LayoutInflater.from(viewGroup.context).inflate(R.layout.item_device, null))
        }
    }

依据viewtype的不同,使用返回的不同的viewholder来填充数据。

override fun myOnBindViewHolder(viewHolder: RecyclerView.ViewHolder, position: Int, viewType: Int) {
        when(viewType){
            ViewType.SEARCH.ordinal->{
                (viewHolder as SearchViewHolder).tv_serach.setOnClickListener {
//                    fragment.context?.startActivity(Intent(fragment.context, SearchActivity::class.java))
                }
            }
            ViewType.BANNER.ordinal->{
            }
            else->{
                val phoneDevice = phoneDevices[position-2]
                (viewHolder as DeviceViewHolder).tv_name.text = phoneDevice.nickName
            }
        }
    }

最后别忘了,返回当前adapter的总数据条目

    override fun myGetItemCount(): Int {
        return phoneDevices.size+2
    }

设备项的数据条数,加上一条搜索框,加上一条banner,一共多加2条。

第三步:为刷新控件设置adapter,并设置数据加载回调

新建刚才自定义的adapter

        val adapter=MyDeviceAdapter(this)
        refreshLayout.setAdapter(adapter)

之前说过,recyclerview的显示格式是由layoutmanager来实现的,经常不需要修改,这里就需要进行修改了,根据之前的设计,整个页面包括一行搜索框、一行banner,剩下的都是每行两列的设备项数据,LinearManager只能实现单列布局显然不符合要求。这里使用GridLayoutManager来实现当前需求,我们要求数据以两列的网格布局进行排列,但是第一、二、最后一列要求每个数据对应的视图占据两列,在两列的网格中就是占据一行的效果了,从而达到我们的目的。

val layoutManager=GridLayoutManager(context,2)
        layoutManager.spanSizeLookup=object : GridLayoutManager.SpanSizeLookup() {
            override fun getSpanSize(position: Int): Int {
                return when(position){
                    0,1,adapter.myGetItemCount()->2
                    else->1
                }
            }
        }
        refreshLayout.setLayoutManager(layoutManager)

最后要为刷新控件加上数据加载的回调,并在回调中进行adapter中数据的设置或添加

refreshLayout.onLoadDataListener=object :OnLoadDataListener{
            override fun refresh(refreshLayout: RefreshLayout) {
                refreshLayout.finishLoad()
            }

            override fun loadMore(refreshLayout: RefreshLayout) {
                var devicesList= ArrayList<PhoneDevice>()
                devicesList.add(PhoneDevice().apply { nickName="哈哈" })
                devicesList.add(PhoneDevice().apply { nickName="测试" })
                devicesList.add(PhoneDevice().apply { nickName="机器" })
                devicesList.add(PhoneDevice().apply { nickName="不错" })
                adapter.addData(devicesList)
            }
        }

运行,效果就出来了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值