JavaRush /Java-Blog /Random-DE /Komplexe Listen leicht gemacht
Paul Soia
Level 26
Kiyv

Komplexe Listen leicht gemacht

Veröffentlicht in der Gruppe Random-DE
Hallo zusammen. Ich habe beschlossen, das Thema komplexer Listen in Android anzusprechen. Dieses Thema hat mich zunächst verwirrt. Es schien mir sehr schwierig, aber eigentlich ist alles einfacher. Und ich denke, dass jeder, der jetzt mit diesem Problem konfrontiert ist, den Artikel nützlich finden wird. Alle Beispiele sind in Kotlin geschrieben. Ich habe versucht, überall Kommentare zu schreiben und sie für diejenigen, die in Java schreiben, so klar wie möglich zu machen. Hier ist also unsere Klassenstruktur: Komplexe Listen leicht gemacht – 1MainActivity- Dies ist die Hauptklasse. ListAdapter- Hier binden wir unsere Liste an Ansichtselemente. ViewHolder(es gibt mehrere davon) – das ist unser Markup für jeden Elementtyp. Elementklassen sind Daten für eine Liste (Pojo). XML-Dateien sind Markups ( activity_mainfür den Hauptbildschirm, der Rest für jeden Listenelementtyp). Als Erstes müssen wir eine Abhängigkeit hinzufügen, damit wir Listen verwenden können (aus irgendeinem Grund fehlt diese Abhängigkeit beim Erstellen eines Projekts). In der Datei build.gradleim Block dependenciesfügen wir die Zeile hinzu:
implementation "androidx.recyclerview:recyclerview:1.1.0"
Als nächstes finden wir die Datei activity_main.xml: Komplexe Listen leicht gemacht – 2Hier gibt es nur unser Element für Listen - RecyclerView. Je nach Geschmack fügen wir Einzüge und Formatierungen hinzu. Als nächstes erstellen wir die Klasse BaseViewHolder. Es wird abstrakt sein, da alle unsere Klassen davon erben werden ViewHolder. Es ist durchaus möglich, darauf zu verzichten, ich empfehle aber dennoch, darauf zu achten, dass alle erbenden Klassen vom Aufbau her gleich sind. (in Kotlin extendsund implementwird stattdessen verwendet :. Wie in Java können Sie hier von einer Klasse erben und viele Schnittstellen implementieren) Als nächstes erstellen wir unsere Datenklassen: ItemTitle, ItemGoogleund ItemApple. In Java sind dies gewöhnliche Klassen mit einem Konstruktor und Gettern.
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
Konzentrieren wir uns hier auf die Schnittstelle ListMarker.
//это наш маркер. Его должны реализовать все айтемы, которые будут
//отображаться в конечном итоге в списке
interface ListMarker
Alle unsere Datenklassen implementieren diese Schnittstelle, um sie in denselben Typ umzuwandeln. Wir werden dies später für unsere Liste benötigen. Als nächstes erstellen wir unsere Viewholder für jedes Element der Liste. Vergessen Sie nicht, dass jeder von ihnen von erbt BaseViewHolder. In diesen Klassen legen wir fest, welches Element viewdem Feld aus den Datenklassen entspricht.
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()
    }
}
Hier gibt es keine besondere Logik, alles ist extrem einfach. Außerdem hat jeder Viewholder sein eigenes Layout: list_item_title.xmlKomplexe Listen leicht gemacht – 3list_item_google.xmlKomplexe Listen leicht gemacht – 4list_item_apple.xmlKomplexe Listen leicht gemacht – 5Kommen wir nun zum schwierigsten Teil – 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
    //Wie вариант можно было сделать 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<*>
Wenn wir unsere Klasse von erben RecyclerView.Adapter, müssen wir drei Methoden überschreiben: onCreateViewHolder, getItemCount, onBindViewHolder. onCreateViewHolder- Hier initialisieren wir unsere Klassen ViewHolder. getItemCount— Diese Methode ist für die Listengröße verantwortlich. onBindViewHolder- Hier übergeben wir die Listenelemente an unsere Klassen ViewHolder. Für eine reguläre Liste mit einem Elementtyp würde dies ausreichen. Aber für verschiedene Typen müssen wir die Methode noch neu definieren getItemViewType(dafür verwenden wir die Konstanten, die oben in unserer Adapterklasse stehen. In Java können Sie finaldafür Variablen verwenden). Auch in Java können Sie onBindViewHolderanstelle eines Ausdrucks einen regulären Ausdruck verwenden . Und schließlich kommen wir zu unserer Hauptklasse – . whenifMainActivity
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>
RecyclerViewHier wird unser und initialisiert ListAdapter. Dies ist ein hübscher Standardcode, auf den viele gestoßen sind. In der Methode stubDatahabe ich die Liste mit Daten gefüllt (wie Sie sehen können, Daten mit unterschiedlichen Elementen) und diese Liste an den Adapter übergeben. Als nächstes starten wir unsere Anwendung und auf unserem Bildschirm sollte etwa Folgendes angezeigt werden: Komplexe Listen leicht gemacht – 6Wie Sie sehen, gibt es in einer Liste verschiedene Elemente, was unser Ziel war. PS: Ich habe vergessen, das zu erwähnen Extension. So sieht es aus:
//это расширение для класса ViewGroup. Теперь мы можем по всему проекту использовать
//короткое inflate anstatt длинного LayoutInflater.from(context).inflate
fun ViewGroup.inflate(@LayoutRes layoutRes: Int, attachToRoot: Boolean = false): View =
    LayoutInflater.from(context).inflate(layoutRes, this, attachToRoot)
Dies ist keine Klasse, sondern eine Datei, weshalb sie keinen Namen enthält. Aber jetzt können wir es einfach im Adapter inflateanstelle einer langen Struktur verwenden. Leider ist dies für Java nicht vorgesehen, also schreiben Sie LayoutInflater.from(context).inflate. Das ist alles. Bis zum nächsten Mal :) Link zu GitHub
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION