Untuk menampilkan daftar data yang kami gunakan RecyclerView
(- Terima kasih, cap!). Dia tahu banyak hal dari kotak dan blablab terkenal lainnya. Tapi ada banyak rasa sakit dengannya. Tidak ada yang suka menulis kode boilerplate yang sama. Dan aku tidak benar-benar ...

Sejarah singkat plot "Kurangi kode sedikit"

Misalnya, Orang kelas data sederhana () dibuat: dengan nama depan, nama belakang, email. ketersediaan surat dan anjing.
Untuk menampilkan daftar orang, Anda harus membuat RecyclerView.Adapter
dan RecyclerView.ViewHolder
, sebagian besar kode + yang sama.
Adapter
ViewHolder
-, . , , ViewHolder
, .
Adapter
ViewHolder
, .
RecyclerView.Adapter<RecyclerView.ViewHolder>
Adapter . , .class ClassicAdapter : RecyclerView.Adapter<ClassicHolder>() {
private val viewModel = PersonItemViewModel()
private val data: List<Person>
get() = viewModel.data
fun setData(persons: List<Person>) {
viewModel.data = persons
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ClassicHolder =
ClassicHolder.create(parent)
override fun getItemCount(): Int = data.size
override fun onBindViewHolder(holder: ClassicHolder, position: Int) {
holder.bind(viewModel, position)
}
}
ViewHolder MVVM.class ClassicHolder(private val binding: ItemPersonBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(viewModel: PersonItemViewModel, position: Int) {
binding.setVariable(BR.viewModel, viewModel)
binding.setVariable(BR.position, position)
binding.executePendingBindings()
}
companion object {
fun create(parent: ViewGroup): ClassicHolder {
val inflater = LayoutInflater.from(parent.context)
val binding: ItemPersonBinding =
DataBindingUtil.inflate(inflater, R.layout.item_person, parent, false)
return ClassicHolder(binding)
}
}
}
item_person.xml binding-: ViewModel Position - RecyclerView.<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="position"
type="Integer" />
<variable
name="viewModel"
type="plus.yeti.prostoadapter.ui.main.PersonItemViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:text="@{viewModel.getName(position)}"
... />
<TextView
android:text="@{viewModel.getEmail(position)}"
.../>
<ImageView
app:visible="@{viewModel.hasDog(position)}"
.../>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
PersonItemViewModel .class PersonItemViewModel : ProstoViewModel<Person>() {
override var data: List<Person> = emptyList()
fun getName(position: Int) = data[position].lastName + ", " + data[position].firstName
fun getEmail(position: Int) = data[position].email
fun hasDog(position: Int): Boolean = data[position].hasDog
}
ProstoAdapter
ProstoHolder
, Adapter
ViewHolder
, .
ProstoViewModel
. , ProstoViewModel
, , , . ViewModel
-:
abstract class ProstoViewModel<T>: ViewModel() {
abstract var data: List<T>
}
ProstoHolder
open class ProstoHolder<TBinding : ViewDataBinding>(val binding: TBinding) : RecyclerView.ViewHolder(binding.root) {
open fun <TData, TViewModel : ProstoViewModel<TData>> bind(viewModel: TViewModel, position: Int) {
binding.setVariable(BR.viewModel, viewModel)
binding.setVariable(BR.position, position)
binding.executePendingBindings()
}
companion object {
fun <TBinding : ViewDataBinding> create(parent: ViewGroup, layoutId: Int): ProstoHolder<TBinding> {
val inflater = LayoutInflater.from(parent.context)
val binding: TBinding = DataBindingUtil.inflate(inflater, layoutId, parent, false)
return ProstoHolder(binding)
}
}
}
, , ProstoAdapter
:
abstract class ProstoAdapter<TBinding : ViewDataBinding, TData> : RecyclerView.Adapter<ProstoHolder<TBinding>>() {
abstract val viewModel: ProstoViewModel<TData>
abstract val layoutId: Int
private var dataSize: Int = 0
open fun setData(data: List<TData>) {
this.dataSize = data.size
viewModel.data = data
notifyDataSetChanged()
}
open var onBind: ((ProstoHolder<TBinding>) -> Unit)? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProstoHolder<TBinding> =
ProstoHolder.create(parent, layoutId)
override fun getItemCount(): Int = dataSize
override fun onBindViewHolder(holder: ProstoHolder<TBinding>, position: Int) {
holder.bind(viewModel, position)
onBind?.invoke(holder)
}
}
Adapter
-a ViewModel
c , item's layout id
Binding-, layout
-, item-.
, :)
class MainFragment : Fragment() {
private val adapter =
object : ProstoAdapter<ItemPersonBinding, Person>() {
override val viewModel = PersonItemViewModel()
override val layoutId = R.layout.item_person
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
mainRecyclerView.adapter = adapter
}
fun setNewPersonList(persons: List<Person>){
adapter.setData(personList)
}
}
4 .
github.com/klukwist/Prosto
ViewHolder-.
:)