JavaRush /Java Blog /Random-TL /Pinadali ang mga kumplikadong listahan
Paul Soia
Antas
Kiyv

Pinadali ang mga kumplikadong listahan

Nai-publish sa grupo
Kamusta kayong lahat. Nagpasya akong itaas ang paksa ng mga kumplikadong listahan sa Android. Ang paksang ito ay naging palaisipan sa akin noong una. Tila napakahirap para sa akin, ngunit ang lahat ay talagang mas simple. At sa palagay ko ang sinumang nahaharap ngayon sa problemang ito ay magiging kapaki-pakinabang ang artikulo. Ang lahat ng mga halimbawa ay nakasulat sa Kotlin. Sinubukan kong magsulat ng mga komento sa lahat ng dako at gawin itong malinaw hangga't maaari para sa mga nagsusulat sa Java. Kaya narito ang aming istraktura ng klase: Pinadali ang mga kumplikadong listahan - 1MainActivity- Ito ang pangunahing klase. ListAdapter- dito namin itali ang aming listahan upang tingnan ang mga elemento. ViewHolder(may ilan sa kanila) - ito ang aming markup para sa bawat uri ng elemento. Ang mga klase ng item ay data para sa isang listahan (pojo). Ang mga Xml file ay mga markup ( activity_mainpara sa pangunahing screen, ang natitira para sa bawat uri ng elemento ng listahan). Ang unang bagay na kailangan nating gawin ay magdagdag ng dependency upang magamit natin ang mga listahan (sa ilang kadahilanan ay nawawala ang dependency na ito kapag lumilikha ng isang proyekto). Sa file build.gradlesa block dependenciesidagdag namin ang linya:
implementation "androidx.recyclerview:recyclerview:1.1.0"
Susunod na hanapin namin ang file activity_main.xml: Pinadali ang mga kumplikadong listahan - 2Narito lamang ang aming elemento para sa mga listahan - RecyclerView. Nagdaragdag kami ng anumang mga indent at pag-format sa panlasa. Susunod na gagawin namin ang klase BaseViewHolder. Ito ay magiging abstract, dahil ang lahat ng aming mga klase ay magmamana mula dito ViewHolder. Ito ay lubos na posible na gawin nang wala ito, ngunit inirerekomenda ko pa rin na tiyakin na ang lahat ng pagmamana ng mga klase ay pareho sa istraktura. (sa Kotlin, extendsat implementginagamit sa halip na :. Tulad ng sa Java, dito maaari kang magmana mula sa isang klase at magpatupad ng maraming mga interface) Susunod, lumikha kami ng aming mga klase ng data: ItemTitle, ItemGoogleat ItemApple. Sa Java, ito ay mga ordinaryong klase na may constructor at 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
Tumutok tayo sa interface dito ListMarker.
//это наш маркер. Его должны реализовать все айтемы, которые будут
//отображаться в конечном итоге в списке
interface ListMarker
Ang lahat ng aming mga klase ng data ay nagpapatupad ng interface na ito upang i-cast ang mga ito sa parehong uri. Kakailanganin namin ito mamaya para sa aming listahan. Susunod, gagawa kami ng aming mga viewholder para sa bawat elemento ng listahan. Huwag kalimutan na ang bawat isa sa kanila ay nagmamana mula sa BaseViewHolder. Sa mga klaseng ito, tinukoy namin kung aling elemento viewang tumutugma sa field mula sa mga klase ng 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()
    }
}
Walang partikular na lohika dito, ang lahat ay sobrang simple. Gayundin, ang bawat viewholder ay may sariling layout: list_item_title.xmlPinadali ang mga kumplikadong listahan - 3list_item_google.xmlPinadali ang mga kumplikadong listahan - 4list_item_apple.xmlPinadali ang mga kumplikadong listahan - 5Ngayon ay lumipat tayo sa pinakamahirap na bahagi - 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<*>
Kapag minana namin ang aming klase mula sa RecyclerView.Adapter, kakailanganin naming i-override ang tatlong pamamaraan: onCreateViewHolder, getItemCount, onBindViewHolder. onCreateViewHolder- dito natin sinisimulan ang ating mga klase ViewHolder. getItemCount— ang pamamaraang ito ay responsable para sa laki ng listahan. onBindViewHolder- dito ipinapasa namin ang mga elemento ng listahan sa aming mga klase ViewHolder. Para sa isang regular na listahan na may isang uri ng elemento, ito ay sapat na. Ngunit para sa iba't ibang uri kailangan pa rin naming muling tukuyin ang pamamaraan getItemViewType(para dito ginagamit namin ang mga constant na nasa tuktok ng aming klase ng adaptor. Sa Java maaari kang gumamit ng finalmga variable para dito). Gayundin sa Java, onBindViewHoldersa halip na isang expression, whenmaaari kang gumamit ng isang regular na if. At sa wakas, lumipat tayo sa aming pangunahing klase - 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>
Dito nasimulan ang ating RecyclerViewat ListAdapter. Ito ay isang magandang boilerplate code na naranasan ng marami. Sa pamamaraan, stubDatapinunan ko ang listahan ng data (tulad ng nakikita mo, data na may iba't ibang elemento) at ipinasa ang listahang ito sa adaptor. Susunod, ilulunsad namin ang aming application, at dapat naming makita ang isang bagay na tulad nito sa aming screen: Pinadali ang mga kumplikadong listahan - 6Gaya ng nakikita mo, may iba't ibang elemento sa isang listahan, na aming layunin. PS Nakalimutang banggitin ang Extension. Ito ang hitsura nito:
//это расширение для класса 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)
Ito ay hindi isang klase, ngunit isang file, kaya naman walang pangalan sa loob nito. Ngunit ngayon ay maaari na nating gamitin ito sa adapter inflatesa halip na isang mahabang istraktura. Sa kasamaang palad, hindi ito ibinigay para sa Java, kaya isulat ang LayoutInflater.from(context).inflate. Iyon lang. Hanggang sa susunod :) Link sa GitHub
Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION