舊機寶開發筆記之:自定義刷新控件(兼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)
            }
        }

運行,效果就出來了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章