強大而靈活的RecyclerView Adapter——BRVAH(框架引入與BaseQuickAdapter使用篇)
theme: channing-cyan
本文正在參加「金石計劃 . 瓜分6萬現金大獎」
前言
接觸到BRVAH是因為我們開發專案中就用到它的BaseQuickAdapter,寫Adapter的確好用,不過一看版本是2x的,所以去框架釋出Github官方程式碼庫(CymChad/BaseRecyclerViewAdapterHelper: BRVAH:Powerful and flexible RecyclerAdapter (github.com))學習了一下最新的4x版本。下面我們就來看看最新的BRVAH如何使用。
正篇
概況
BRVAH (recyclerview.org)是可以在Android中更方便實現Adapter的RecyclerAdapter框架,它的引入可以節省大量開發時間,
它封裝了許多好用的功能,如:點選事件、資料操作、動畫、空檢視,載入更多等
引入框架
目前該框架已經更新到4x版本,但需要注意這個框架從2x到3x已經不完全相容,而3x到4x也是不相容的,但4x有著前幾代都沒有的優勢,它引入更容易,因為v4版本已經上傳 maven 中央倉庫,不需要再引入三方倉庫配置了。
Gradle
implementation "io.github.cymchad:BaseRecyclerViewAdapterHelper:4.0.0-beta04"
直接引入到app的build.gradle檔案中的dependencies依賴中即可
BaseQuickAdapter的使用
本文章Demo更新在AndroidStudyman/StudyDemo: Study demo (github.com)專案中,使用方法參考文件:BaseQuickAdapter · CymChad/BaseRecyclerViewAdapterHelper Wiki (github.com)
引入框架後,我們可以看到BaseQuickAdapter原始碼如下:
```Kotlin
class AdapterDemo : BaseQuickAdapter
//自定義ViewHolder類
class VH(
parent: ViewGroup,
binding: LayoutPageAdapterDemoBinding = LayoutPageAdapterDemoBinding.inflate(
LayoutInflater.from(parent.context), parent, false
)
) : RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
// 返回一個 ViewHolder
return VH(parent)
}
override fun onBindViewHolder(holder: VH, position: Int, item: ModelDemoItem?) {
// 設定item資料
item?.getItemName()
}
} ```
上面的程式碼已更新到(StudyDemo/AdapterDemo.kt at main · AndroidStudyman/StudyDemo (github.com))中
我們建立一個AdapterDemo類去繼承BaseQuickAdapter,然後寫一個VH類去繫結Viewbinding,可以自定義item資料型別,當然,也可以不用我的例子,使用官方教程中不用ViewBinding的方式去寫,使用QuickViewHolder:
```Kotlin
class TestAdapter : BaseQuickAdapter
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): QuickViewHolder {
// 返回一個 ViewHolder
return QuickViewHolder(R.layout.layout_animation, parent)
}
override fun onBindViewHolder(holder: QuickViewHolder, position: Int, item: Status?) {
// 設定item資料
}
}
其中adapter中對應的VH中binding的佈局如下:
XML
接下來,這是我寫的item列表的屬性類:
Kotlin
class ModelDemoItem(
var name : String? = null,
var age: Int) {
fun getItemName() : String? {
return name
}
fun getItemAge() : Int {
return age
}
}
用於設定item列表每項展示的資料:
override fun onBindViewHolder(holder: VH, position: Int, item: ModelDemoItem?) {
// 設定item資料
val name = holder.itemView.findViewById我們在每項中添加了name和age資料,然後在adapter中onBindViewHolder()方法設定到對應佈局中:
class ActivityAdapterDemo : AppCompatActivity() {
val tag : String = "ActivityAdapterDemo"
private lateinit var binding : ActivityAdapterDemoBinding
private lateinit var adapterDemo: AdapterDemo
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityAdapterDemoBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.vAdapterList.layoutManager = LinearLayoutManager(this)
val itemBeans: ArrayList<ModelDemoItem> = ArrayList()
for (i in 0..49) {
itemBeans.add(ModelDemoItem("Name $i", i))
}
adapterDemo = AdapterDemo()
adapterDemo.submitList(itemBeans)
binding.vAdapterList.adapter = adapterDemo
...
}
}
上面的程式碼就是在我們在RecyclerView中繫結Aapter,並往裡面填充資料,我們呼叫BaseQuickAdapter的submitList方法填充資料,RecyclerView所在的Activity檢視佈局如下:
XML
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
android:text="@string/adapter_demo"
android:textColor="@color/black"
android:textSize="16sp"
app:autoSizeMaxTextSize="16sp"
app:autoSizeMinTextSize="8dp"
app:autoSizeTextType="uniform"
android:maxLines="1"/>
</LinearLayout>
<LinearLayout
android:layout_width="56dp"
android:layout_height="56dp">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="@string/next"
android:visibility="invisible"/>
</LinearLayout>
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/vAdapterList"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
我們可以在Activity中的adapter例項化物件中呼叫相應的點選事件,長按事件以及為子項也新增對應的事件監聽:
Kotlin
//item 長按事件
adapterDemo.setOnItemLongClickListener { adapter, view, position ->
Log.i(tag, " setOnItemLongClickListener ${adapter.hashCode()}, ${view.tag}, $position ")
val intent = Intent(this, MainActivity ::class.java)
intent.action = Intent.ACTION_VIEW
true
}
//item 子控制元件點選事件 // 需要傳遞控制元件 id adapterDemo.addOnItemChildClickListener(R.id.vName) { adapter, view, position -> Log.i(tag, " addOnItemChildClickListener ${adapter.hashCode()}, ${view.tag}, $position ") Toasty.info( baseContext, "addOnItemChildClickListener!").show() }
//item 子控制元件長按事件 // 需要傳遞控制元件 id adapterDemo.addOnItemChildLongClickListener(R.id.vAge) { adapter, view, position -> Log.i(tag, " addOnItemChildLongClickListener ${adapter.hashCode()}, ${view.tag}, $position ") Toasty.info( baseContext, "addOnItemChildLongClickListener!!").show() true
} ``` 除了設定資料集合的submitList()方法,還有很多十分方便的資料設定方法,如下:
修改某一位置的資料
Kotlin
val item = ModelDemoItem("Name 6", 6)
//修改index為1處的資料
adapterDemo[1] = item
新增資料
```Kotlin // 尾部新增資料 adapterDemo.add(item)
// 在指定位置新增一條新資料 adapterDemo.add(1, item)
//val itemBeans: ArrayList
// 指定位置新增資料集 adapterDemo.addAll(1, itemBeans) ```
刪除資料
```Kotlin // 刪除資料 adapterDemo.remove(item)
// 刪除指定位置資料 adapterDemo.removeAt(1) ```
交換資料位置
Kotlin
// 交換兩個位置的資料
adapterDemo.swap(1, 3)
獲取Item資料的索引
Kotlin
// 如果返回 -1,表示不存在
adapterDemo.getItemPosition(item)
根據索引,獲取Item資料
Kotlin
// 如果返回 null,表示沒有資料
adapterDemo.getItem(1)
以上都是資料的操作方法,按需所取就行,但要注意一些方法中資料操作的合理性,防止出現存取過界的情況發生
新增動畫
內建了五種動畫:
Kotlin
/**
* BaseQuickAdapter.AnimationType.AlphaIn
* BaseQuickAdapter.AnimationType.ScaleIn
* BaseQuickAdapter.AnimationType.SlideInBottom
* BaseQuickAdapter.AnimationType.SlideInLeft
* BaseQuickAdapter.AnimationType.SlideInRight
*/
adapterDemo.setItemAnimation(BaseQuickAdapter.AnimationType.AlphaIn)
原始碼如下:
AlphaIn:淡入專案的動畫,在預設 300 毫秒內以統一速率將 alpha 從預設 0f 更改為 1.0f\ ScaleIn:縮放專案的動畫,在預設 300 毫秒內將專案的 scaleX 和 scaleY 從預設的 0.5f 更改為 1.0f。(使用具有預設因子的 DecelerateInterpolator)\ SlideInBottom:讓專案從底部滑入的動畫。(使用因子為 1.3 的 DecelerateInterpolator)預設持續時間為 400 毫秒。\ SlideInLeft:讓專案從左側滑入的動畫。(使用因子為 1.8 的 DecelerateInterpolator)預設持續時間為 400 毫秒。\ SlideInRight:讓專案從右側滑入的動畫。(使用因子為 1.8 的 DecelerateInterpolator)預設持續時間為 400 毫秒。\ 其中DecelerateInterpolator是一種減速插值器,是一種變化率從很快變慢的插值器。
官方也明確舉例可以自定義動畫:
```Kotlin class CustomAnimation1 : ItemAnimator { override fun animator(view: View): Animator { // 建立三個動畫 val alpha: Animator = ObjectAnimator.ofFloat(view, "alpha", 0f, 1f) val scaleY: Animator = ObjectAnimator.ofFloat(view, "scaleY", 1.3f, 1f) val scaleX: Animator = ObjectAnimator.ofFloat(view, "scaleX", 1.3f, 1f)
scaleY.interpolator = DecelerateInterpolator()
scaleX.interpolator = DecelerateInterpolator()
// 多個動畫組合,可以使用 AnimatorSet 包裝
val animatorSet = AnimatorSet()
animatorSet.duration = 350
animatorSet.play(alpha).with(scaleX).with(scaleY)
return animatorSet
}
}
// 設定動畫
adapter.itemAnimation = CustomAnimation1()
然後在Adapter類中設定startItemAnimator方法來重寫動畫執行操作:
Kotlin
override fun startItemAnimator(anim: Animator, holder: RecyclerView.ViewHolder) {
}
``` 還有用於決定是否啟用動畫的方法:
Kotlin
adapterDemo.animationEnable = true
載入空佈局
空檢視只會在無資料的情況下顯示
-
使用
Layout Id
Kotlin adapterDemo.setEmptyViewLayout(context, R.layout.loading_view)
-
使用
View
mAdapter.emptyView = view
-
注意:如果你使用
GridLayoutManager
,請切換至QuickGridLayoutManager
,否則空佈局無法鋪滿
還有更多用法可以檢視官方文件:BaseQuickAdapter · CymChad/BaseRecyclerViewAdapterHelper Wiki · GitHub,已經寫的很詳細了,只是沒有完整的Demo,本文就是依據此文件實現的Demo。
總結
因為工作中開發經常使用到,但沒想到內容這麼多,這只是最常用的部分,此外,還有多型別佈局Adapter等等
不過官方的4x版本也在繼續寫文件,敬請期待吧,當然也可以去看看官方提供的Demo:BRVAH-v4.apk - 藍奏雲 (lanzouj.com),不過不知道為什麼是個APK應用,不是專案形式。
- 安卓開發一年技術小結——安卓開發技術整理
- 安卓Kotlin開發學習——接著看高階函式
- 兔兔按鈕——安卓懸浮按鈕
- 兔兔進度條Plus——SeekBar充當Progress
- 安卓基礎開發——ReentrantLock的簡單使用
- 安卓開發基礎——使用RecyclerView
- 安卓開發基礎(Java)——TextView的使用
- 安卓開發基礎——弱引用的使用
- 安卓開發基礎——實現音訊檔案的播放
- 讓UI忙碌的安卓Lottie動畫渲染庫(二)
- 強大而靈活的RecyclerView Adapter——BRVAH(框架引入與BaseQuickAdapter使用篇)
- 安卓語言基礎之Kotlin的面向物件程式設計
- 安卓語言基礎之Kotlin高階函式——Lambda表示式(二)
- 大放光彩的安卓Jetpack元件-ViewModel(一)
- 安卓語言基礎之Kotlin高階函式——Lambda表示式(一)
- 安卓開發必備——build.gradle檔案初探(一)
- 安卓開發學Flutter——Dart語法的一些注意點(第二篇)
- 簡單易用的安卓SharedPreferences儲存(資料儲存系列)
- 安卓開發基礎技術——WebView載入網頁
- 原汁原味的安卓檔案儲存(資料儲存系列)