JavaRush /Blog Jawa /Random-JV /Dhaptar Komplek digawe gampang
Paul Soia
tingkat
Kiyv

Dhaptar Komplek digawe gampang

Diterbitake ing grup
Halo kabeh. Aku mutusake kanggo ngunggahake topik dhaptar kompleks ing Android. Topik iki saya bingung ing wiwitan. Iku ketoke angel banget kanggo kula, nanging kabeh iku bener prasaja. Lan aku mikir yen sapa wae sing saiki ngadhepi masalah iki bakal nemokake artikel kasebut migunani. Kabeh conto ditulis ing Kotlin. Aku nyoba nulis komentar ing endi-endi lan nggawe kanthi jelas kanggo sing nulis nganggo basa Jawa. Dadi iki struktur kelas kita: Dhaptar Komplek digawe gampang - 1MainActivity- Iki kelas utama. ListAdapter- kene kita njiret dhaftar kita kanggo ndeleng unsur. ViewHolder(ana sawetara) - iki markup kita kanggo saben jinis unsur. Kelas item minangka data kanggo dhaptar (pojo). File Xml minangka markup ( activity_mainkanggo layar utama, liyane kanggo saben jinis unsur dhaptar). Wangsulan: Bab ingkang sapisanan kudu kita tindakake iku nambah dependensi supaya kita bisa nggunakake dhaptar (saperangan alesan iki ketergantungan ilang nalika nggawe proyek). Ing file build.gradleing blok dependencieskita nambah baris:

implementation "androidx.recyclerview:recyclerview:1.1.0"
Sabanjure, kita nemokake file kasebut activity_main.xml: Dhaptar Komplek digawe gampang - 2Ing kene mung ana unsur kanggo dhaptar - RecyclerView. Kita nambah indents lan format kanggo rasa. Sabanjure kita nggawe kelas BaseViewHolder. Iku bakal abstrak, amarga kabeh kelas kita bakal oleh warisan saka iku ViewHolder. Iku cukup bisa kanggo nindakake tanpa iku, nanging aku isih menehi saran manawa kabeh kelas warisan padha ing struktur. (ing Kotlin, extendslan implementdigunakake tinimbang :. Kaya ing Jawa, kene sampeyan bisa oleh warisan saka siji kelas lan ngleksanakake akeh antarmuka) Sabanjure, kita nggawe kelas data kita: ItemTitle, ItemGooglelan ItemApple. Ing Jawa, iki minangka kelas biasa kanthi konstruktor lan getter.

data class ItemGoogle(
    val name: String,
    val product: String,
    val version: String,
    val isUse: Boolean
) : ListMarker

data class ItemApple(
    val name: String,
    val country: String,
    val year: Int
) : ListMarker

data class ItemTitle(
    val title: String,
    val amount: Int
) : ListMarker
Ayo dadi fokus ing antarmuka kene ListMarker.

//это наш маркер. Его должны реализовать все айтемы, которые будут
//отображаться в конечном итоге в списке
interface ListMarker
Kabeh kelas data kita ngleksanakake antarmuka iki kanggo matak menyang jinis padha. Kita bakal mbutuhake iki mengko kanggo dhaptar kita. Sabanjure, kita nggawe viewholders kanggo saben unsur dhaptar. Aja lali yen saben wong duwe warisan saka BaseViewHolder. Ing kelas kasebut, kita nemtokake unsur viewsing cocog karo lapangan saka kelas data.

abstract class BaseViewHolder<t>(itemView: View) : RecyclerView.ViewHolder(itemView) {
    abstract fun bind(item: T)
}

class GoogleViewHolder(view: View) : BaseViewHolder<itemgoogle>(view) {

    override fun bind(item: ItemGoogle) {
        itemView.tvName.text = item.name
        itemView.tvProduct.text = item.product
        itemView.tvVersion.text = item.version
        if (item.isUse) {
            itemView.tvProduct.visibility = View.GONE
        } else {
            itemView.tvProduct.visibility = View.VISIBLE
        }
    }
}

class AppleViewHolder(view: View) : BaseViewHolder<itemapple>(view) {

    override fun bind(item: ItemApple) {
        //можем делать так
        itemView.tvName.text = item.name
        itemView.tvCountry.text = item.country
        itemView.tvYear.text = item.year.toString()

        /*----сверху и снизу два идентичных блока----*/

        //а можем сделать такой блок и не использовать в каждой строке itemView
        with(itemView) {
            tvName.text = item.name
            tvCountry.text = item.country
            tvYear.text = item.year.toString()
        }
    }
}

class TitleViewHolder(view: View) : BaseViewHolder<itemtitle>(view) {

    override fun bind(item: ItemTitle) {
        itemView.tvTitle.text = item.title
        itemView.tvAmount.text = item.amount.toString()
    }
}
Ora ana logika tartamtu ing kene, kabeh gampang banget. Uga, saben viewholder duwe tata letak dhewe: list_item_title.xmlDhaptar Komplek digawe gampang - 3list_item_google.xmlDhaptar Komplek digawe gampang - 4list_item_apple.xmlDhaptar Komplek digawe gampang - 5Saiki ayo pindhah menyang bagean sing paling angel - ListAdapter.

class ListAdapter : RecyclerView.Adapter<baseviewholder<*>>() {

    companion object {
        //задаем константы для каждого типа айтема
        private const val TYPE_TITLE = 0
        private const val TYPE_GOOGLE = 1
        private const val TYPE_APPLE = 2
    }

    //здесь можно использовать обычный ArrayList
    //сюда добавляются все айтемы, которые реализовали интерфейс ListMarker
    //How вариант можно было сделать mutableListOf<any>() и обойтись без интерфейса
    private val items = mutableListOf<listmarker>()

    internal fun swapData(list: List<listmarker>) {
        items.clear()
        items.addAll(list)
        notifyDataSetChanged()
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<*> {
        return when(viewType) {
            //задаем разметку для каждого типа айтема
            TYPE_TITLE -> TitleViewHolder(parent.inflate(R.layout.list_item_title))
            TYPE_GOOGLE -> GoogleViewHolder(parent.inflate(R.layout.list_item_google))
            TYPE_APPLE -> AppleViewHolder(parent.inflate(R.layout.list_item_apple))
            else -> throw IllegalArgumentException("Invalid view type")
        }
    }

    override fun getItemViewType(position: Int): Int {
        return when (items[position]) {
            is ItemTitle -> TYPE_TITLE
            is ItemGoogle -> TYPE_GOOGLE
            is ItemApple -> TYPE_APPLE
            else -> throw IllegalArgumentException("Invalid type of item $position")
        }
    }

    override fun getItemCount(): Int {
        //этот метод определяет размер списка
        return items.size
    }

    override fun onBindViewHolder(holder: BaseViewHolder<*>, position: Int) {
        val element = items[position]
        when (holder) {
            //отправляем каждый айтем к своему ViewHolder
            is TitleViewHolder -> holder.bind(element as ItemTitle)
            is GoogleViewHolder -> holder.bind(element as ItemGoogle)
            is AppleViewHolder -> holder.bind(element as ItemApple)
            else -> throw IllegalArgumentException()
        }
    }
}
</listmarker></listmarker></any></baseviewholder<*>
Nalika kita marisi kelas kita saka RecyclerView.Adapter, kita kudu ngilangi telung cara: onCreateViewHolder, getItemCount, onBindViewHolder. onCreateViewHolder- ing kene kita miwiti kelas kita ViewHolder. getItemCount- cara iki tanggung jawab kanggo ukuran dhaftar. onBindViewHolder- ing kene kita ngirim unsur dhaptar menyang kelas kita ViewHolder. Kanggo dhaptar biasa kanthi siji jinis unsur, iki bakal cukup. Nanging kanggo macem-macem jinis kita isih kudu redefine cara getItemViewType(kanggo iki kita nggunakake konstanta ing ndhuwur kelas adaptor kita. Ing Jawa sampeyan bisa nggunakake finalvariabel kanggo iki). Uga ing Jawa, onBindViewHoldertinimbang ekspresi, whensampeyan bisa nggunakake if. Lan pungkasane, ayo pindhah menyang kelas utama - MainActivity.

class MainActivity : AppCompatActivity() {

    private val adapter = ListAdapter()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        initRecyclerView()
    }

    private fun initRecyclerView() {
        rvList.layoutManager = LinearLayoutManager(this)

        //здесь мы задаем разделитель между айтемами, чтоб они не сливались друг с другом
        val divider = DividerItemDecoration(this, LinearLayoutManager.VERTICAL)
        rvList.addItemDecoration(divider)

        rvList.adapter = adapter
        stubData()
    }

    private fun stubData() {
        val list = mutableListOf<listmarker>()
        list.add(ItemTitle("title1", 4))
        list.add(ItemGoogle("android", "product1", "17.0v", true))
        list.add(ItemGoogle("no name", "product2", "3.1v", false))
        list.add(ItemApple("macOs", "USA", 2005))
        list.add(ItemApple("iOs", "China", 2007))
        list.add(ItemTitle("title2", 2))
        list.add(ItemGoogle("map", "product3", "23.0v", true))
        list.add(ItemApple("car", "England", 2018))
        list.add(ItemTitle("title3", 0))
        //отправляем все данные в адаптер
        adapter.swapData(list)
    }
}
</listmarker>
RecyclerViewIki ngendi kita lan iki initialized ListAdapter. Iki minangka kode boilerplate sing akeh ditemoni. Ing cara, stubDataaku ngisi dhaptar data (kaya sing sampeyan deleng, data karo unsur sing beda) lan ngirim dhaptar iki menyang adaptor. Sabanjure, kita miwiti aplikasi kita, lan kita kudu ndeleng kaya iki ing layar: Dhaptar Komplek digawe gampang - 6Kaya sing sampeyan ngerteni, ana macem-macem unsur ing siji dhaptar, sing dadi tujuane. PS Kelalen nyebutake Extension. Iki katon kaya:

//это расширение для класса ViewGroup. Теперь мы можем по всему проекту использовать
//короткое inflate instead of длинного LayoutInflater.from(context).inflate
fun ViewGroup.inflate(@LayoutRes layoutRes: Int, attachToRoot: Boolean = false): View =
    LayoutInflater.from(context).inflate(layoutRes, this, attachToRoot)
Iki dudu kelas, nanging file, mulane ora ana jeneng ing njero. Nanging saiki kita bisa nggunakake ing adaptor mung inflatetinimbang struktur dawa. Sayange, iki ora kasedhiya kanggo Jawa, supaya nulis LayoutInflater.from(context).inflate. Mekaten. Nganti mbesuk :) Link menyang GitHub
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION