Hallo liebe Leser. Wir alle Liebe und verwenden Sie die Databinding , die Google vor einigen Jahren eingeführt, das Datenmodell zu Ansichten durch das Ansichtsmodell zu verknüpfen. In diesem Artikel möchte ich Ihnen mitteilen, wie Sie diesen Prozess mithilfe der Kotlin-Sprache vereinheitlichen und die Erstellung von Adaptern für RecyclerView (im Folgenden: RV), ViewPager und ViewPager2 in mehreren Codezeilen anpassen können.
Zunächst haben wir benutzerdefinierte Adapter entwickelt, die von ViewHolders unter der Haube erstellt wurden, und das Schreiben und noch mehr Unterstützung hat viel Zeit in Anspruch genommen. Unten finden Sie ein Beispiel für einen typischen RV-Adapter:
class CustomAdapter(private val dataSet: Array<String>) : RecyclerView.Adapter<CustomAdapter.ViewHolder>() {
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val textView: TextView
init {
textView = view.findViewById(R.id.textView)
}
}
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(viewGroup.context).inflate(R.layout.text_row_item, viewGroup, false)
return ViewHolder(view)
}
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) { // Get element from your dataset at this position and replace the
viewHolder.textView.text = dataSet[position]
}
override fun getItemCount() = dataSet.size
}
Wenn das Projekt wächst, gibt es möglicherweise noch viel mehr dieser Adapter. Ich erinnere mich einmal, dass der Adapter so riesig war, mehrere hundert Codezeilen, dass es enorm lange dauerte, um herauszufinden, was dort geschah, und noch mehr, um etwas Neues hinzuzufügen, da er mit verschiedenen Datenmodellen funktionierte und auch musste für jeden Datentyp unterschiedliche Zuordnungen erstellen . Um ehrlich zu sein, war es schwer.
DataBinding , , onCreateViewHolder
, LayoutInflater
, DataBindingUtil.inflate
, .
class BindingViewHolder(val binding: ItemTextRowBinding) : RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingViewHolder {
val binding = DataBindingUtil.inflate<ItemTextRowBinding>(LayoutInflater.from(parent.context), viewType, parent, false)
val viewHolder = BindingViewHolder(binding)
return viewHolder
}
override fun onBindViewHolder(holder: BindingViewHolder, position: Int) {
holder.binding.setVariable(BR.item, dataSet[position])
}
, RV, , . BindingAdapter androidx.databinding. , , RV, - DataBindingRecyclerViewConfig
, .
, EasyRecyclerBinding. BindingAdapters ViewPager ViewPager2. :
1) , , , RV, - app:items
app:rv_config
.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="vm"
type="com.rasalexman.erb.ui.base.ExampleViewModel" />
<variable
name="rvConfig"
type="com.rasalexman.easyrecyclerbinding.DataBindingRecyclerViewConfig" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="0dp"
android:layout_height="0dp"
app:items="@{vm.items}"
app:rv_config="@{rvConfig}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:listitem="@layout/item_recycler"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
ViewModel, , , RV, DataBindingRecyclerViewConfig.
//
class ExampleViewModel : ViewModel() {
val items: MutableLiveData<MutableList<RecyclerItemUI>> = MutableLiveData()
}
data class RecyclerItemUI(
val id: String,
val title: String
)
, , .
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="item"
type="com.rasalexman.erb.models.RecyclerItemUI" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:drawable/list_selector_background">
<TextView
android:id="@+id/titleTV"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingTop="8dp"
android:paddingEnd="16dp"
android:textColor="@color/black"
android:textSize="18sp"
android:text="@{item.title}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Hello world" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:paddingBottom="8dp"
android:textColor="@color/gray"
android:textSize="14sp"
android:text="@{item.id}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/titleTV"
tools:text="Hello world" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
2) dataBinding, - createRecyclerConfig<I : Any, BT : ViewDataBinding>
, DataBindingRecyclerViewConfig, id , , .
class RecyclerViewExampleFragment : BaseBindingFragment<RvExampleFragmentBinding, ExampleViewModel>() {
override val layoutId: Int get() = R.layout.rv_example_fragment
override val viewModel: ExampleViewModel by viewModels()
override fun initBinding(binding: RvExampleFragmentBinding) {
super.initBinding(binding)
binding.rvConfig = createRecyclerConfig<RecyclerItemUI, ItemRecyclerBinding> {
layoutId = R.layout.item_recycler
itemId = BR.item
}
}
}
, , ViewModel RV. , onItemClick, onItemCreate, onItemBind
.
, , EasyRecyclerBinding - IBindingModel
layoutResId
, - id , .
data class RecyclerItemUI(
val id: String,
val title: String
) : IBindingModel {
override val layoutResId: Int
get() = R.layout.item_recycler
}
data class RecyclerItemUI2(
val id: String,
val title: String
) : IBindingModel {
override val layoutResId: Int
get() = R.layout.item_recycler2
}
, , - createRecyclerMultiConfig
, .
class RecyclerViewExampleFragment : BaseBindingFragment<RvExampleFragmentBinding, RecyclerViewExampleViewModel>() {
override val layoutId: Int get() = R.layout.rv_example_fragment
override val viewModel: RecyclerViewExampleViewModel by viewModels()
override fun initBinding(binding: RvExampleFragmentBinding) {
super.initBinding(binding)
binding.rvConfig = createRecyclerMultiConfig {
itemId = BR.item
}
}
}
class RecyclerViewExampleViewModel : BasePagesViewModel() {
open val items: MutableLiveData<MutableList<IBindingModel>> = MutableLiveData()
}
, RV, , , , , presentation . , , , , .
Ein ähnlicher Prozess zum Erstellen von Adaptern für ViewPager und ViewPager2 wird in einem Beispiel auf Github zusammen mit Open Source vorgestellt, einem Link, auf den ich am Ende des Artikels gepostet habe. Derzeit wird die Bibliothek noch fertiggestellt, und ich würde gerne ein angemessenes Feedback und Wünsche für ihre weitere Entwicklung erhalten. Es enthält auch Zusatzfunktionen zum bequemen Erstellen von Geboten, auch in Verbindung mit dem ViewModel. (LayoutInflater.createBinding, Fragment.createBindingWithViewModel usw.)
Danke fürs Lesen bis zum Ende. Viel Spaß beim Codieren und gute Laune