基於Kotlin和雙向數據綁定特性的RecycleView框架

介紹

代碼量最少, 使用便捷, 非侵入式, 知足常見需求, 同時方便擴展和自定義.android

特性

  • 使用Databinding構建MVVM
  • 完美擁有Kotlin的特性
  • 通用適配器
  • 方便實現常見需求
  • 代碼量最少, 邏輯更清晰.

需求

用最少的代碼實現開發過程當中的常見需求:git

  • 多類型github

    • 單一數據模型一對多
    • 多數據模型
  • 添加頭佈局和腳佈局bash

  • 點擊/長按事件網絡

    • 過濾重複點擊
  • 切換模式app

  • 選擇模式框架

    • 全選/取消全選/反選
    • 單選
    • 監聽選擇事件
  • 拖拽移動異步

  • 側滑刪除maven

  • 下拉刷新 | 上拉加載 (PageRefreshLayout|SmartRefreshLayout)ide

  • 多狀態缺省頁 (PageRefreshLayout)

  • 自動分頁加載 (PageRefreshLayout)

  • 擴展

    • 伸縮佈局 (FlexboxLayoutManager)

    • 自動化網絡請求 (KalleExtension)

      該網絡請求基於Kalle|RxJava|Moshi|LifeCycle|本庫 實現自動化的網絡請求

將來將支持:

  • 無限滾動
  • 分組
    • 展開摺疊
    • 頂部附着

依賴

project of build.gradle

allprojects {
    repositories {
        // ...
        maven { url 'https://jitpack.io' }
    }
}
複製代碼

module of build.gradle

implementation 'com.github.liangjingkanji:BRV:1.0.4'
複製代碼

預覽

home
flex
header

footer
check_mode
footer
refresh
state
swipe_drag

初始化

class MyApplication : Application() {

    override fun onCreate() {
        super.onCreate()
      
        BindingAdapter.modelId = BR.m // 推薦在Application中進行初始化或使用以前便可
    }
}
複製代碼

LayoutManager

快速建立佈局管理器

fun RecyclerView.linear( @RecyclerView.Orientation orientation: Int = VERTICAL, reverseLayout: Boolean = false )


fun RecyclerView.grid( spanCount: Int, @RecyclerView.Orientation orientation: Int = VERTICAL, reverseLayout: Boolean = false )

fun RecyclerView.staggered( spanCount: Int, @RecyclerView.Orientation orientation: Int = VERTICAL )
複製代碼

多類型

不一樣數據模型

rv.linear().setup {

  addType<Model>(R.layout.item_1)
  addType<Store>(R.layout.item_2)

}.models = data
複製代碼

一對多數據模型

開發中經常遇到一個列表, 列表每一個數據對應的一個字段來判斷itemType

addType<Model>{
  // 使用年齡來做爲判斷返回不一樣的佈局
  when (age) {
    23 -> {
      R.layout.item_1
    }
    else -> {
      R.layout.item_2
    }
  }
}
複製代碼

分割線

快速實現分割線

fun RecyclerView.divider( @DrawableRes drawable: Int, @RecyclerView.Orientation orientation: Int = RecyclerView.VERTICAL, block: ((Rect, View, RecyclerView, RecyclerView.State) -> Boolean)? = null
)
複製代碼

監聽事件

監聽事件須要先添加想要監聽的view

fun addClickable(@IdRes vararg id: Int)
// 過濾500毫秒內重複點擊

fun addFastClickable(@IdRes vararg id: Int)
// 區別於上面函數不過濾重複點擊事件

fun addLongClickable(@IdRes vararg id: Int)
// 長按事件
複製代碼

事件回調

onClick{

}
// 點擊事件

onLongClick{

}
// 長按點擊事件

onBind {
  
  false
}
複製代碼

onBind屬於onBindViewHolder事件監聽.

若是你須要本身去設置數據或綁定事件就使用該函數. 返回值決定是否用框架內部默認的Databinding綁定佈局. false表示不綁定.

更簡單的寫法示例

rv.linear().setup {

    addType<Model>{
        R.layout.item_1
    }

    onClick(R.id.item, R.id.user_portrait){

    }


    onLongClick(R.id.item){

    }

}.models = data
複製代碼

頭佈局/腳佈局

頭佈局和腳佈局在rv中算做一個item, 因此計算position的時候應當考慮其.

操做頭佈局

fun addHeader(view: View)

fun removeHeader(view: View)

fun clearHeader()

fun isHeader(@IntRange(from = 0) position: Int): Boolean
複製代碼

操做腳佈局

fun addFooter(view: View)

fun removeFooter(view: View)

fun clearFooter()

fun isFooter(@IntRange(from = 0) position: Int): Boolean
複製代碼

獲取數據

val headerCount: Int

val footerCount: Int
複製代碼

獲取數據的最終手段不是隻有一種而已能夠存在對重對稱加密手段

切換模式

切換模式至關於會提供一個回調函數遍歷全部的item, 你能夠在這個回調函數裏面依次刷新他們.

經常使用於切換選擇模式.

fun toggle()
// 切換模式

fun getToggleMode(): Boolean
// 範圍當前出何種切換模式

fun setToggleMode(toggleMode: Boolean)
// 設置切換模式, 若是設置的是當前正處於的模式不會觸發回調
複製代碼

回調函數

onToggle { type, position, toggleMode ->  // 類型 位置 切換布爾值
	// 在這裏能夠給item刷新成選擇模式
}

// 切換完成
onToggleEnd {
	// 例如切換工具欄爲選擇模式
}
複製代碼

選擇模式

check_mode

fun allChecked()
// 全選

fun allChecked(isAllChecked: Boolean)
// 全選或者所有取消全選

fun clearChecked()
// 取消全選

fun reverseChecked() 
// 反選

fun setChecked(@IntRange(from = 0) position: Int, checked: Boolean)
// 設置某個item的選擇狀態

fun toggleChecked(@IntRange(from = 0) position: Int)
// 切換某個item的選擇狀態

fun <M> getCheckedModels(): List<M>

fun setCheckableType(@LayoutRes vararg checkableItemType: Int)
// 設置哪些type容許進入選擇狀態

val checkedCount: Int
複製代碼

拖拽/側滑

只支持拖拽移動和側滑刪除

步驟:

  1. 開啓ItemTouchHelper支持
  2. 數據模型繼承ItemModel
  3. 自定義擴展

BindingAdapter提供一個字段來開啓ItemTouchHelper支持

var touchEnable = false // 默認關閉
複製代碼

而後數據模型要求繼承ItemModel, 根據需求重寫函數.

示例:

data class Model(val name: String) : ItemModel() {

    override fun getDrag(): Int {
        return UP or DOWN
    }

    override fun getSwipe(): Int {
        return RIGHT or LEFT
    }
    
}
複製代碼

RIGHT or LEFT是控制拖拽和側滑的方向(側滑不支持UP/DOWN)的常量.

拖拽移動item會自動改變數據模型在數據集合中的位置.

擴展功能

若是想要擴展ItemTouchHelper能夠給BindingAdapter的變量itemTouchHelper賦值

rv.linear().setup {

  addType<Model>(R.layout.item)
  touchEnable = true
  
  itemTouchHelper = ItemTouchHelper(object : DefaultItemTouchCallback(this) {
			// 這裏能夠重寫函數
  })

}.models = data
複製代碼

經過給view打上tag標籤 swipe 能夠控制側滑將會移動的視圖.

<RelativeLayout android:layout_width="wrap_content" android:layout_height="80dp" android:orientation="horizontal" android:tag="swipe"/>
複製代碼

缺省頁

內部依賴 StateLayout, 該庫支持任意 Activity | Fragment | View 實現缺省頁功能.

主要特色

  • 全局配置
  • 單例配置
  • 生命週期(能夠加載動畫或者處理事件)
  • 支持activity/fragment/view替換
  • 支持代碼或者XML實現
  • 無網絡狀況下showLoading顯示錯誤佈局, 有網則顯示加載中佈局

本庫已經依賴, 無需再次依賴. 使用方法見GitHub.

PageRefreshLayout

該佈局擴展自 SmartRefreshLayout(該庫強烈推薦使用), 支持其全部特性.

本庫已引入SmartRefreshLayout 'com.scwang.smart:refresh-layout-kernel:2.0.0-alpha-1', 無需再次引入.

針對須要的請求頭能夠去其開源地址分包引入.

在此基礎上增長特性

  • 缺省頁
  • 自動分頁加載
  • 支持KT特性
  • 代碼替換

建立方式

// 1. 代碼建立, 經過擴展函數
val page = rv.page()

// 2. 佈局包裹
<com.drake.brv.PageRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/page" app:stateEnabled="true" android:layout_height="match_parent" tools:context="com.drake.brv.sample.fragment.RefreshFragment">

    <androidx.recyclerview.widget.RecyclerView android:id="@+id/rv" android:layout_width="match_parent" android:layout_height="match_parent" />

</com.drake.brv.PageRefreshLayout>
複製代碼

監聽狀態

// 下拉刷新
page.onRefresh {
	// 這裏能夠進行網絡請求等異步操做
}

// 上拉加載
page.onLoadMore {
	// 這裏能夠進行網絡請求等異步操做
}
複製代碼

若是onLoadMore 不調用則上拉加載一樣也會回調onRefresh函數, 由於下拉刷新和上拉加載可能都是走的同一個網絡請求.

缺省頁

觸發刷新狀態(二者都會回調函數onRefresh)

  1. autoRefesh 這是觸發的下拉刷新
  2. showLoading 這是觸發的加載頁面, 固然得先設置loadingLayout(或者讀取全局缺省頁配置)
  3. refresh 靜默刷新, 不會觸發任何動畫s

第二種方式通常用於初次進入頁面時候加載數據, 這三種方式都會致使索引index=startIndex重置.

其餘狀態控制

showEmpty()
showError()
showContent
複製代碼

配置全局缺省頁

這塊代碼和StateLayout公用

/** * 推薦在Application中進行全局配置缺省頁, 固然一樣每一個頁面能夠單獨指定缺省頁. * 具體查看 https://github.com/liangjingkanji/StateLayout */
StateConfig.apply {
  emptyLayout = R.layout.layout_empty
  errorLayout = R.layout.layout_error
  loadingLayout = R.layout.layout_loading

  onLoading {
    // 今生命週期能夠拿到LoadingLayout建立的視圖對象, 能夠進行動畫設置或點擊事件.
  }
}
複製代碼

單例缺省頁配置支持兩種方式

  1. XML
<com.drake.brv.PageRefreshLayout ..... app:stateEnabled="true" app:error_layout="@layout/layout_error" app:empty_layout="@layout/layout_empty" app:loading_layout="@layout/layout_loading">
複製代碼
  1. 代碼
page.apply {
    loadingLayout = R.layout.layout_loading
    emptyLayout = R.layout.layout_empty
    errorLayout = R.layout.layout_error

    stateEnabled = true
}
複製代碼

兩個方式能夠看到都須要執行stateEnabled = true這個函數, 不然無效. 若是不設置單例就會顯示默認的全局缺省頁

想要使用缺省頁又要求缺省頁不遮蓋頭佈局, 請使用CoordinatorLayout. 使用NestedScrollView會致使rv沒法複用item.

刷新數據

前面提到 PageRefreshLayout 支持自動分頁加載

// 設置分頁加載第一頁的索引, 默認=1, 觸發刷新會重置索引.
PageRefreshLayout.startIndex = 0 

page.onRefresh {

  // 這是網絡請求
  post("/path") {
		addParames("key", "value")
  }.net(activity) {
    // 該回調函數參數返回一個布爾類型用於判斷是否存在下一頁, 決定上拉加載的狀態.
    addData(data, { adapter.count < data.page }) 
  }

}
複製代碼

若是感受網絡請求的代碼很優雅, 能夠關注個人Github網絡請求庫.

相關文章
相關標籤/搜索