RecyclerViewAdapter
重新定义 RecyclerView Adapter 的封装,追求既简单又实用,结合 Kotlin 的高级特性,优化代码书写方式,真正做到高内聚低耦合
开源地址
Github RecyclerViewAdapter
框架设计核心思想
- 摒弃 notifyDataSetChanged 无脑操作,利用 ObservableList 自动匹配数据,并实现局部刷新
- 真正通用的 ViewHolder 抽象,从此只关注 Layout XML 布局
- 真正通用的 Adapter,从此不再写 Adapter 子类
- ItemViewType 自动匹配对象 Layout XML,不再关心它的细节
- 科学的分包处理,真正做到框架的各取所需(一般列表只需引用 Adapter-core 核心库即可)
- 扩展 Anko Layout 版本,体验 Anko Layout 的魅力,并能获取高于 XML 加载至少 3 倍以上的效率提升
- 像堆积木一样,将页面的每个模块都做到了复用,跟 Fragment 可以说再见
设计图
规划
核心库 Core 的完善Anko 扩展- FlexboxLayout 扩展
- SortedList 扩展
- paging 3 扩展
- DiffUtil 扩展
- DataBinding 扩展
- 等等.. 未来有好的想法继续扩展
环境需要
- Kotlin
- JAVA
- AndroidX
抱歉目前按照最新的 AndroidX 适配的,如有其他需要请私聊我。
怎么用
ArrayListAdapter
step1
创建 xml 布局, 和之前一样的布局方式
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:layout_margin="5dp">
<LinearLayout
android:background="?attr/selectableItemBackground"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="5dp"
android:orientation="vertical">
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/colorPrimary"
android:textSize="22sp" />
<TextView
android:id="@+id/tv_subTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/colorAccent"
android:textSize="18sp" />
</LinearLayout>
</androidx.cardview.widget.CardView>
step2
定义 ViewModel 及 Model,可以看到,逻辑简单明了,刷新自己的时候只需要更新 Model,并 reBindView 即可,刷新别人的话,需要通过 Adapter 去更新,复杂页面只需要再新建一个 ArrayItemViewModel 的子类即可,并创建一个新的 XML 布局,从这里的代码可以看出,同样一个 ViewModel 未来可以复用很多 XML 布局,完全做到了 ViewModel、View、Model 三个角色的任意复用。为业务多样化提供最底层的支持。
/**
* Model
*/
data class ModelTest(var title: String, var subTitle: String)
/**
* ViewModel
*/
class ArrayViewModelTest : ArrayItemViewModel<ModelTest>() {
var index = 0
override fun onBindView(adapter: ArrayListAdapter?) {
viewHolder.itemView.apply {
tv_title.text = model.title
tv_subTitle.text = model.subTitle
cardItem.setOnClickListener {model.title = "${index++}"
reBindView()}
}
}
override fun getLayoutRes() = R.layout.item_test}
复用逻辑如下图:
step3
Activity 中增删改,增删改都是对 ViewModel 层的操作,简单实用。
/**
* Activity
*/
class ArrayListActivity : AppCompatActivity() {
private val mArrayListAdapter by lazy {ArrayListAdapter()
}
override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)
setContentView(R.layout.activity_array_list)
rv_list.bindListAdapter(mArrayListAdapter)
// 新增一个
new_add.setText("新增").setOnClickListener {mArrayListAdapter.add(ArrayViewModelTest().apply {model = ModelTest("标题", "副标题")
})
}
// 删除第一个
delete.setText("删除").setOnClickListener {if (mArrayListAdapter.size > 0)
mArrayListAdapter.removeAt(0)
else
toast("请添加新用例后再试")
}
// 随机更新
var updateSize = 0
update.setText("更新").setOnClickListener {
updateSize++
if (mArrayListAdapter.size > 0) {val randomInt = Random.nextInt(0, mArrayListAdapter.size)
mArrayListAdapter.set(randomInt, ArrayViewModelTest().apply {model = ModelTest("标题 $updateSize", "副标题 $updateSize")
})
} else {toast("请添加新用例后再试")
}
}
}
}
AnkoListAdapter
step1
定义 AnkoLayout
/**
* AnkoItemView
*/
class AnkoItemView() : AnkoComponent<ViewGroup> {
var tvTitle: TextView? = null
var tvSubTitle: TextView? = null
@SuppressLint("ResourceType")
override fun createView(ui: AnkoContext<ViewGroup>) = with(ui) {
cardView {
layoutParams = FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT
).apply {margin = dip(5)
}
verticalLayout {val typedValue = TypedValue()
context.theme
.resolveAttribute(android.R.attr.selectableItemBackground, typedValue, true)
val attribute = intArrayOf(android.R.attr.selectableItemBackground)
val typedArray =
context.theme.obtainStyledAttributes(typedValue.resourceId, attribute)
background = typedArray.getDrawable(0)
layoutParams = FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT
).apply {padding = dip(10)
}
tvTitle = textView {textSize = px2dip(60)
textColorResource = R.color.colorPrimary
}.lparams(matchParent, wrapContent)
tvSubTitle = textView {textSize = px2dip(45)
textColorResource = R.color.colorAccent
}.lparams(matchParent, wrapContent)
}
}
}
}
step2
定义 ViewModel,Model
/**
* Model
*/
data class ModelTest(var title: String, var subTitle: String)
/**
* ViewModel
*/
class AnkoViewModelTest : AnkoItemViewModel<ModelTest, AnkoItemView>() {
var index = 0
override fun onBindView(adapter: AnkoListAdapter) {
ankoView.tvTitle?.text = model.title
ankoView.tvSubTitle?.text = model.subTitle
viewHolder.itemView.setOnClickListener {model.title = "${index++}"
reBindView()}
}
override fun onCreateView(): AnkoItemView {return AnkoItemView()
}
}
step3
Activity 中增删改
/**
* Activity
*/
class AnkoLayoutActivity : AppCompatActivity() {
private val mAnkoListAdapter by lazy {AnkoListAdapter()
}
override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)
AnkoLayoutComponent(mAnkoListAdapter).setContentView(this).apply {
// 新增一个
new_add.setText("新增").setOnClickListener {mAnkoListAdapter.add(AnkoViewModelTest().apply {model = ModelTest("标题", "副标题")
})
}
// 删除第一个
delete.setText("删除").setOnClickListener {if (mAnkoListAdapter.size > 0)
mAnkoListAdapter.removeAt(0)
else
toast("请添加新用例后再试")
}
// 随机更新
var updateSize = 0
update.setText("更新").setOnClickListener {
updateSize++
if (mAnkoListAdapter.size > 0) {val randomInt = Random.nextInt(0, mAnkoListAdapter.size)
mAnkoListAdapter.set(randomInt, mAnkoListAdapter.getItem(randomInt).apply {
model.also {
it as ModelTest
it.title = "$updateSize"
}
})
} else {toast("请添加新用例后再试")
}
}
}
}
}
/**
* View
*
*/
class AnkoLayoutComponent(private val ankoListAdapter: AnkoListAdapter) : AnkoComponent<AnkoLayoutActivity> {override fun createView(ui: AnkoContext<AnkoLayoutActivity>) = with(ui) {
verticalLayout {
recyclerView {bindListAdapter(ankoListAdapter)
}.lparams(matchParent) {weight = 1F}
// Anko 兼容 xml 布局的加载
include<View>(R.layout.include_button_bottom)
}
}
}
上一篇博客
一个资深的 Android 是不是应该学会自己做一个超级的 RecyclerView.Adapter
开发者
-
i 校长
- Jetpack.net.cn
- 简书
- 掘金