Prosto: إزالة لوحة مرجعية عند العمل مع RecyclerView

لعرض قائمة البيانات التي نستخدمها RecyclerView(- شكرا لك ، كاب!). إنه يعرف الكثير من الأشياء من العلبة وغيرها من blablabs المعروفة. ولكن هناك الكثير من الألم معه. لا أحد يحب كتابة نفس الرمز المعياري. وأنا لست حقًا ...



نبذة تاريخية عن المؤامرة "تقليل الرمز قليلاً":



على سبيل المثال ، تم إنشاء فئة بيانات بسيطة Person (): بالاسم الأول واسم العائلة والبريد الإلكتروني. توفر البريد والكلب.


لعرض قائمة من الناس، يجب عليك إنشاء RecyclerView.Adapterو RecyclerView.ViewHolder، فإن معظم الذين + كود هو نفسه.


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-.


:)


All Articles