Úlohy pre 4. cvičenie

  • 1. Vylepšenie dizajnu aplikácie.
  • 2. Použitie prekladov v aplikácii.
  • 3. Vytvorenie skrolovateľného zoznamu položiek pomocou RecyclerView.

Hodnotenie

Prve hodnotenie aplikacii bude na 5. cviceni, kde treba mat hotove vsetky ulohy pre moznost ziskania max. poctu bodov.

1. Vylepšenie dizajnu aplikácie.

Krok 1: Pochopte hierarchiu štýlov

Androidová hierarchia štýlov je organizovaná tak, aby umožňovala konzistentnosť dizajnu a zároveň flexibilitu pre jednotlivé komponenty. Táto hierarchia má tri hlavné časti:

  • Zobrazené atribúty (View Attributes): Sú to vlastnosti, ktoré môžete nastaviť priamo na jednotlivé komponenty (views) vo vašom XML layoute. Sú to najkonkrétnejšie nastavenia, ktoré majú najvyššiu prioritu.
  • Štýly (Styles): Štýly sú zoskupenia zobrazených atribútov. Môžete si predstaviť štýl ako "predlohu" alebo "súbor" nastavení, ktoré sa môžu opakovane použiť na rôzne komponenty v layoute.
  • Témy (Themes): Sú to kolekcie štýlov a zobrazených atribútov, ktoré sa aplikujú na celú aplikáciu alebo časti aplikácie. Témy nastavujú všeobecný vzhľad a pocit aplikácie.

Je dôležité si uvedomiť: Ak sa rovnaký atribút definuje vo View, v štýle a v téme, atribút z View má najvyššiu prioritu (tzn. prekryje ostatné), štýl má strednú prioritu a téma má najnižšiu prioritu. Inými slovami, Zobrazené atribúty prepíšu Štýly, a Štýly prepíšu Témy.

Krok 2: Používanie zobrazených atribútov

Každý komponent (view) vo vašom layoute môže mať atribúty. Tieto atribúty môžu byť špecifikované priamo v XML súbore layoutu.

Napríklad, ak chcete, aby váš TextView mal červený text veľkosti 18sp, môžete nastaviť tieto atribúty priamo:

<TextView
    android:text="Ahoj svet!"
    android:textColor="#FF0000"
    android:textSize="18sp" 
    ... />

Ak nastavíte štýl alebo tému s inými hodnotami pre tieto atribúty, tieto hodnoty z TextView budú mať prednosť.

Krok 3: Vytvorenie a použitie štýlu

Štýly umožňujú znovu použiť skupinu atribútov naprieč rôznymi komponentami. Znížite tak redundanciu a zjednodušíte úpravy dizajnu.

Vytvorte štýl v súbore res/values/styles.xml:

<style name="TextStyle">
    <item name="android:textColor">#FF0000</item>
    <item name="android:textSize">18sp</item>
</style>

Použite štýl v komponente:

<TextView
    android:text="Ahoj svet!"
    style="@style/TextStyle"
    ... />

Krok 4: Vytvorenie a použitie témy

Témy definujú celkový vzhľad vašej aplikácie. Aplikujú sa buď na celú aplikáciu alebo len na časti aplikácie.

Vytvorenie témy v res/values/styles.xml:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="colorPrimary">#3F51B5</item>
    <item name="colorPrimaryDark">#303F9F</item>
    <item name="colorAccent">#FF4081</item>
</style>

Aplikácia témy pre aplikáciu v AndroidManifest.xml:

<application
    android:theme="@style/AppTheme"
    ... />

Krok 5: Dedičnosť štýlov a prepisovanie

Predstavte si, že máte základný štýl textu, ktorý chcete použiť na viacerých miestach vo vašej aplikácii, ale s niekoľkými malými zmenami v niektorých prípadoch.

Vytvoríme základný štýl textu v res/values/styles.xml:

<style name="BaseTextStyle">
    <item name="android:textSize">16sp</item>
    <item name="android:textColor">#000000</item>
</style>

Ak chcete vytvoriť variáciu tohto štýlu s väčšou veľkosťou textu, môžete vytvoriť nový štýl, ktorý dedí z "BaseTextStyle" a prepíše požadovaný atribút:

<style name="LargeTextStyle" parent="BaseTextStyle">
    <item name="android:textSize">24sp</item>
</style>

Keď použijete štýl LargeTextStyle na TextView v XML layoute, tento TextView bude mať čiernu farbu textu (zdedenú z BaseTextStyle) a veľkosť 24sp (prepisuje základný štýl).

Krok 6: Implementácia nočného režimu

Nočný režim umožňuje zmeniť vzhľad aplikácie podľa denného času alebo nastavení zariadenia. Aby ste podporili nočný režim, môžete definovať špecifické štýly a témy pre tento režim.

Vytvorenie štýlu pre nočný režim v res/values-night/styles.xml:

<style name="TextStyleNight">
    <item name="android:textColor">#FFFFFF</item>
    <item name="android:textSize">18sp</item>
</style>

Pri aktivovanom nočnom režime sa automaticky použije tento štýl, ak je nastavený na komponente.

Krok 7: Pochopte a použite dp a sp

dp (Density-independent Pixels): Je to jednotka, ktorá sa používa na určenie rozmieru komponentu nezávisle od hustoty obrazovky. Umožňuje konzistentný vzhľad naprieč rôznymi zariadeniami.

sp (Scale-independent Pixels): Je to jednotka používaná pre text. Podobne ako dp, ale berie do úvahy aj nastavenia veľkosti textu užívateľa.

Je dôležité používať tieto jednotky pre dosiahnutie konzistentného a prispôsobivého dizajnu naprieč rôznymi zariadeniami.

Krok 8: Používanie Material Design

Material Design je dizajnový jazyk vyvinutý Google. Poskytuje sadu komponentov, štýlov a usmernení pre vývoj kvalitných Android aplikácií. Ak chcete začať používať Material Design, pridajte závislosť v `build.gradle`:

implementation(libs.material)

Použitie Material Button

XML:
<com.google.android.material.button.MaterialButton
    android:id="@+id/materialButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Stlač ma!"
    app:cornerRadius="8dp" />
Kotlin:
val button = findViewById<MaterialButton>(R.id.materialButton)
button.setOnClickListener { 
    // kód po stlačení tlačidla 
}


Použitie Material Floating Action Button (FAB)

XML:
<com.google.android.material.floatingactionbutton.FloatingActionButton
    android:id="@+id/fab"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:contentDescription="@string/description"
    app:srcCompat="@drawable/ic_add_white_24dp" />
Kotlin:
val fab = findViewById<FloatingActionButton>(R.id.fab)
fab.setOnClickListener { 
    // kód po stlačení FAB
}


Použitie Material TextInputLayout

XML:
<com.google.android.material.textfield.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="Zadajte text">

    <com.google.android.material.textfield.TextInputEditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</com.google.android.material.textfield.TextInputLayout>


Krok 6: Použitie Material Snackbar

Kotlin:
val view = findViewById<View>(R.id.container)
Snackbar.make(view, "Toto je Snackbar", Snackbar.LENGTH_LONG)
    .setAction("Akcia") {
        // kód po stlačení akcie na Snackbar
    }.show()



3. Použitie prekladov v aplikácii.

Krok 1: Vytvorenie predvolených reťazcových zdrojov

Vaše predvolené reťazce by mali byť definované v res/values/strings.xml. Napríklad:

<resources>
    <string name="app_name">Moja Aplikácia</string>
    <string name="welcome_message">Vitajte v mojej aplikácii!</string>
</resources>

Krok 2: Pridanie prekladov

Ak chcete pridať preklady, vytvorte ďalšie priečinky zdrojových hodnôt pre každý jazyk, ktorý chcete podporovať. Napríklad pre francúzštinu vytvorte priečinok res/values-fr a pre Nemčinu res/values-de.

Pre francúzštinu, res/values-fr/strings.xml môže vyzerať nasledovne:

<resources>
    <string name="app_name">Mon Application</string>
    <string name="welcome_message">Bienvenue dans mon application!</string>
</resources>

Krok 3: Použitie preložených reťazcov v kóde a XML

Pri použití reťazcov v kóde alebo XML, odkazujte sa na nich normálne pomocou @string/app_name. Android automaticky vyberie správny preklad na základe nastavenia jazyka zariadenia.

Krok 4: Testovanie prekladov

Aby ste otestovali rôzne preklady, zmeňte jazyk vášho Android zariadenia alebo emulátora. Uistite sa, že vaša aplikácia správne zobrazuje preložené reťazce.

Ak máte zariadenie s viacerými jazykmi, Android by mal automaticky zvoliť najvhodnejší preklad z dostupných prekladov vo vašej aplikácii.

Krok 5: Udržujte preklady aktuálne

Ak pridáte alebo zmeníte reťazce v predvolenej verzii, uistite sa, že aktualizujete aj všetky preklady. Existujú nástroje a služby, ktoré vám môžu pomôcť synchronizovať a spravovať preklady pre Android aplikácie.

3. Vytvorenie skrolovateľného zoznamu položiek pomocou RecyclerView

Krok 1: Vytvorenie XML layout pre RecyclerView

Tento XML kód je určený pre layout v Android aplikácii a obsahuje dva hlavné komponenty: BottomBar a RecyclerView.

RecyclerView je flexibilná komponenta zobrazenia, ktorá je optimalizovaná pre veľké súbory dát, ktoré sa menia v čase. Tento konkrétny RecyclerView je nastavený tak, aby vyplnil všetok dostupný priestor medzi vrchom rodičovského view a spodnou časťou BottomBar.

V súbore fragment_example.xml:
<eu.mcomputing.mobv.mobvzadanie.BottomBar
    android:id="@+id/bottom_bar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent" />

<androidx.recyclerview.widget.RecyclerView
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toTopOf="@id/bottom_bar"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    android:layout_height="0dp"
    android:layout_width="match_parent"/>

Šírka je nastavená na match_parent, čo znamená, že RecyclerView bude mať rovnakú šírku ako jeho rodičovský view. Výška je nastavená na 0dp, čo v kombinácii s hornými a dolnými obmedzeniami zabezpečuje, že RecyclerView sa rozťahuje, aby vyplnila dostupný vertikálny priestor.

Krok 2: Vytvorenie XML layout pre riadok v zozname

Tento XML kód definuje layout pre jednotlivé riadky zobrazené v rámci komponentu RecyclerView. Skladá sa z ConstraintLayout, ktorý obsahuje ImageView a TextView.

ConstraintLayout je použitý ako kontajner pre riadok, čo umožňuje flexibilné rozmiestnenie a veľkosť komponentov vo vnútri. Tento layout sa rozširuje na celú šírku rodičovského view a obaluje obsah pre výšku.

Okrem toho, margin definovaný v android:layout_margin poskytuje odsadenie od okrajov rodičovského view.

ImageView je použitý pre zobrazenie obrázka v riadku. Jeho šírka a výška sú nastavené na wrap_content, čo znamená, že view si zmení svoje rozmery podľa veľkosti obrázka.

Použitie layout_constraint* atribútov zabezpečuje, že tento view je ukotvený na vrch a začiatok rodičovského view v rámci ConstraintLayout.

TextView je použitý pre zobrazenie textu v riadku. Jeho šírka a výška sú nastavené na wrap_content, čo znamená, že view si zmení svoje rozmery podľa obsahu textu.

Text je posunutý od začiatku obrázka s definovaným odsadením a je ukotvený na vrch rodičovského view.

Vytvorte súbor feed_item.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="@dimen/activity_horizontal_margin"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <ImageView
        android:id="@+id/item_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        />

    <TextView
        android:id="@+id/item_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toEndOf="@id/item_image"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginStart="@dimen/activity_horizontal_margin"
        />

</androidx.constraintlayout.widget.ConstraintLayout>

Krok 3: Implementácia adaptéra

RecyclerView.Adapter je kľúčovou súčasťou práce s RecyclerView v Android aplikáciách. Tento adaptér je zodpovedný za poskytovanie viewholderov, ktoré reprezentujú položky dát, a tiež za väzbu dát k týmto viewholderom keď sú tieto položky zobrazené na obrazovke.

Pred implementáciou adaptéra musíte najprv definovať ViewHolder. Táto vnútorná trieda rozširuje RecyclerView.ViewHolder a uchováva informácie o jednotlivých položkách zoznamu.


class CustomViewHolder(view: View) : RecyclerView.ViewHolder(view) {
    val imageView: ImageView = view.findViewById(R.id.item_image)
    val textView: TextView = view.findViewById(R.id.item_text)
}
        

V tomto príklade, CustomViewHolder obsahuje referencie na ImageView a TextView, ktoré sa používajú na zobrazenie dát pre jednu položku v RecyclerView.

Adaptér potrebuje prepísať tri metódy: onCreateViewHolder(), onBindViewHolder(), a getItemCount().


class CustomAdapter(private val data: List<DataType>) : RecyclerView.Adapter<CustomViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_layout, parent, false)
        return CustomViewHolder(view)
    }

    override fun onBindViewHolder(holder: CustomViewHolder, position: Int) {
        val item = data[position]
        // Bind data to ViewHolder
    }

    override fun getItemCount(): Int = data.size
}
        

V metóde onCreateViewHolder(), adaptér inflates the layout pre každú položku a inicializuje ViewHolder. V metóde onBindViewHolder(), adaptér priradí dáta (získané z vašej dátovej sady) k elementom view udržiavaným ViewHolder-om. Metóda getItemCount() jednoducho vráti počet položiek v dátovej sade.

Nakoniec, po vytvorení adaptéra, musíte ho priradiť k inštancii RecyclerView.


val recyclerView: RecyclerView = findViewById(R.id.my_recycler_view)
recyclerView.adapter = CustomAdapter(myDataList)
recyclerView.layoutManager = LinearLayoutManager(this)
        

Toto priradenie zabezpečuje, že RecyclerView bude vedieť, ako vytvárať a napĺňať jednotlivé riadky na základe dát poskytnutých adaptérom.

Príklad adaptéra: FeedAdapter

Nižšie je príklad adaptéra pre RecyclerView s vlastným layoutom, ktorý obsahuje ImageView a TextView:

Vytvorte nový Kotlin súbor s názvom FeedAdapter.kt a implementujte adaptér.

package eu.mcomputing.mobv.mobvzadanie

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView

data class MyItem(val imageResource: Int, val text: String)

class FeedAdapter : RecyclerView.Adapter<FeedAdapter.FeedViewHolder>() {
    private var items: List<MyItem> = listOf()

    // ViewHolder poskytuje odkazy na zobrazenia v každej položke
    class FeedViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)

    // Táto metóda vytvára nový ViewHolder
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FeedViewHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.feed_item, parent, false)
        return FeedViewHolder(view)
    }

    // Táto metóda prepojí dáta s ViewHolderom
    override fun onBindViewHolder(holder: FeedViewHolder, position: Int) {
        holder.itemView.findViewById<ImageView>(R.id.item_image).setImageResource(items[position].imageResource)
        holder.itemView.findViewById<TextView>(R.id.item_text).text = items[position].text
    }

    // Vracia počet položiek v zozname
    override fun getItemCount() = items.size

    fun updateItems(newItems: List<MyItem>) {
        items = newItems
        notifyDataSetChanged()
    }
}

Tento kód demonštruje, ako vytvoriť adaptér pre RecyclerView, ktorý obsahuje zoznam položiek typu MyItem. Každá položka MyItem má dva atribúty: imageResource pre ukladanie referencie na obrázok a text pre ukladanie textového reťazca.

data class MyItem(val imageResource: Int, val text: String): Definuje dátovú triedu v Kotlin, ktorá reprezentuje položku so dvoma vlastnosťami: obrázok a text.

class FeedAdapter : RecyclerView.Adapter<FeedAdapter.FeedViewHolder>(): Definuje adaptér dedičný od RecyclerView.Adapter s vnorenou triedou FeedViewHolder.

class FeedViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView): Táto vnorená trieda rozširuje RecyclerView.ViewHolder a poskytuje referencie na zobrazenia pre každú položku v RecyclerView.

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FeedViewHolder: Táto metóda inflates (načíta) layout pre každú položku v RecyclerView a inicializuje FeedViewHolder.

override fun onBindViewHolder(holder: FeedViewHolder, position: Int): Táto metóda prepojí dáta s ViewHolderom. Konkrétne nastavuje obrázok a text pre zobrazenia v ViewHolderi na základe dát na aktuálnej pozícii.

override fun getItemCount() = items.size: Táto metóda vracia celkový počet položiek v dátovom zozname.

fun updateItems(newItems: List<MyItem>): Táto verejná metóda umožňuje aktualizovať zoznam položiek v adaptéri a informovať RecyclerView o zmene dát prostredníctvom volania notifyDataSetChanged().

Kód je dobre štrukturovaný a každá časť má svoju zodpovednú úlohu pri zobrazovaní dát v RecyclerView. Metóda updateItems je obzvlášť užitočná, pretože umožňuje adaptéru pracovať s najnovšími dátami.

Krok 4: Inicializácia RecyclerView v Fragment

V súbore fragmentu, inicializujte RecyclerView:
val recyclerView = view.findViewById<RecyclerView>(R.id.feed_recyclerview)
recyclerView.layoutManager = LinearLayoutManager(context)
val feedAdapter = FeedAdapter()
recyclerView.adapter = feedAdapter
feedAdapter.updateItems(listOf(
    MyItem(R.drawable.baseline_feed_24,"Prvy"),
    MyItem(R.drawable.baseline_map_24,"Druhy"),
    MyItem(R.drawable.baseline_account_box_24,"Treti"),
))

Tento úsek kódu ilustruje, ako sa inicializuje RecyclerView a nastavuje sa jeho adaptér a správca rozloženia v kontexte Android aplikácie. Tu je podrobný opis krokov:

  • val recyclerView = view.findViewById<RecyclerView>(R.id.feed_recyclerview): Táto línia kódu vyhľadáva RecyclerView v aktuálnom zobrazení/layoute pomocou jeho ID. Následne priradzuje referenciu na tento RecyclerView do premennej recyclerView.
  • recyclerView.layoutManager = LinearLayoutManager(context): Nastavuje správcu rozloženia pre RecyclerView. LinearLayoutManager zobrazuje položky v lineárnom zozname, čo je štandardný spôsob zobrazenia položiek v zozname alebo mriežke v Android aplikáciách.
  • val feedAdapter = FeedAdapter(): Vytvára novú inštanciu adaptéra FeedAdapter, ktorý bol predtým definovaný. Tento adaptér bude zodpovedný za dodávanie zobrazení položiek pre RecyclerView.
  • recyclerView.adapter = feedAdapter: Priradzuje adaptér feedAdapter k RecyclerView. Týmto sa zabezpečí, že každá položka v zozname bude mať správne zobrazenie, a bude správne zobrazovaná v RecyclerView.
  • feedAdapter.updateItems(listOf( MyItem(R.drawable.baseline_feed_24,"Prvy"), MyItem(R.drawable.baseline_map_24,"Druhy"), MyItem(R.drawable.baseline_account_box_24,"Treti"), )): Tento kód aktualizuje dáta v adaptéri s novým zoznamom položiek. Každá položka je reprezentovaná inštanciou MyItem, ktorá obsahuje obrázok a text. updateItems je metóda definovaná v našom FeedAdapter, ktorá aktualizuje zoznam položiek a informuje adaptér, že dáta sa zmenili.

Tento kód je kľúčový pri inicializácii a nastavení RecyclerView v Android aplikácii, aby sa zobrazovali položky v zozname pomocou custom adaptéra.

LinearLayoutManager je správca rozloženia, ktorý usporiada položky v lineárnej sekvencii. Je jedným z najčastejšie používaných správcov rozloženia v `RecyclerView` a poskytuje jednoduché zobrazenie položiek, buď horizontálne alebo vertikálne. Jeho hlavným cieľom je zobraziť položky v jednom stĺpci alebo riadku, podobne ako tradičný zoznam.

GridLayoutManager umožňuje zobraziť položky v mriežkovom formáte. V závislosti od orientácie a definovaného počtu "spanov" môže tento správca rozloženia usporiadať položky vo viacerých stĺpcoch (vertikálna orientácia) alebo riadkoch (horizontálna orientácia). Je ideálny pre situácie, keď chcete zobraziť položky v mriežkovom formáte, ako sú galérie obrázkov alebo aplikácie s dlaždicovým rozhraním.

Všeobecné vlastnosti

  • Flexibilita: Oba správcovia rozloženia sú flexibilné a môžu byť prispôsobené rôznym potrebám zobrazenia. Ich orientácia, rozmer a ďalšie vlastnosti môžu byť nastavené podľa požiadaviek aplikácie.
  • Optimalizácia: Ako súčasť knižnice RecyclerView, oba správcovia rozloženia sú navrhnuté tak, aby boli výkonné a optimalizované pre veľké súbory dát. Položky, ktoré nie sú viditeľné, sa opätovne použijú, čo znižuje záťaž na systém pri posúvaní.
  • Pripojenie s adaptérom: Oba správcovia rozloženia pracujú v tesnej spolupráci s adaptérom, ktorý poskytuje dáta a definuje, ako sú jednotlivé položky zobrazené.

LinearLayoutManager

LinearLayoutManager je jedným z manažérov rozloženia poskytovaných v rámci knižnice RecyclerView v Androide. Jeho hlavným účelom je zobraziť súbor položiek v lineárnom rozložení, čo môže byť vertikálne alebo horizontálne. Tu je niekoľko kľúčových bodov, ktoré je dôležité vedieť o LinearLayoutManager:

  • Základné Rozloženie: LinearLayoutManager umožňuje položkám v RecyclerView zobrazovať sa v priamke alebo lineárnej sekvencii, podobne ako LinearLayout v klasických Android rozloženiach.
  • Vertikálne alebo Horizontálne: Môžete nastaviť orientáciu LinearLayoutManagera na vertikálnu alebo horizontálnu. Vertikálna orientácia zobrazuje položky zhora nadol, kým horizontálna orientácia zobrazuje položky zľava doprava.
  • Práca s RecyclerView: Aby RecyclerView mohol správne fungovať, potrebuje manažéra rozloženia. LinearLayoutManager je často používaný, keď chcete zobraziť položky ako jednoduchý jeden stĺpec alebo riadok.
  • Účinnosť: LinearLayoutManager recykluje iba tie položky, ktoré momentálne nie sú viditeľné na obrazovke, čím zvyšuje výkon pri posúvaní tým, že znovu používa zobrazenia.
  • Prispôsobivosť: Napriek svojej jednoduchosti je LinearLayoutManager veľmi prispôsobivý. Môže byť použitý v rôznych situáciách, kde je potrebné zobraziť zoznam položiek lineárne.

LinearLayoutManager je dôležitou súčasťou mnohých Android aplikácií, ktoré vyžadujú zobrazenie zoznamu položiek v konzistentnom a účinnom spôsobe. Jeho použitie zjednodušuje správu rozloženia položiek v RecyclerView.

Príklad nastavenia LinearLayoutManager:


val layoutManager = LinearLayoutManager(context)
recyclerView.layoutManager = layoutManager
        

Vertikálna a horizontálna orientácia:

Ak chcete zmeniť orientáciu na horizontálnu, môžete to urobiť takto:


layoutManager.orientation = LinearLayoutManager.HORIZONTAL
        

GridLayoutManager

GridLayoutManager je ďalší manažér rozloženia poskytovaný v rámci knižnice RecyclerView v Androide, ktorý zobrazuje položky v mriežkovom rozložení. Položky sú usporiadané v stĺpcoch a riadkoch, čo poskytuje vizuálne bohatší dojem ako lineárne rozloženie. Tu je niekoľko dôležitých aspektov, ktoré je dobré poznať o GridLayoutManager:

  • Mriežkové Rozloženie: GridLayoutManager rozdeľuje súbor položiek do mriežky, ktorá pozostáva zo stĺpcov a riadkov. Každý riadok obsahuje fixný počet stĺpcov.
  • Prispôsobiteľný Počet Stĺpcov: Môžete nastaviť počet stĺpcov v mriežke, čo je užitočné pre rôzne veľkosti displejov alebo orientácie zariadenia (na stojato alebo na ležato).
  • Integrácia s RecyclerView: Podobne ako LinearLayoutManager, aj GridLayoutManager je používaný s RecyclerView pre zobrazenie položiek, ale poskytuje mriežkové rozloženie namiesto lineárneho.
  • Recyklácia Zobrazení: GridLayoutManager tiež recykluje zobrazenia tým, že opätovne používa položky, ktoré sa stali neviditeľnými v dôsledku posúvania.
  • Flexibilita: Je možné prispôsobiť veľkosti položiek, meniť orientáciu rozloženia a dokonca umožniť rôzne typy zobrazení v rámci jednej mriežky s použitím GridLayoutManager.

GridLayoutManager je ideálny pre aplikácie, ktoré potrebujú zobraziť položky v mriežkovom formáte, ako sú galérie obrázkov alebo komplexnejšie rozhrania. Poskytuje flexibilitu a vysoký výkon pre interaktívne a vizuálne prvky aplikácie.

Príklad nastavenia GridLayoutManager s 3 stĺpcami:


val gridLayoutManager = GridLayoutManager(context, 3)
recyclerView.layoutManager = gridLayoutManager
        

Ak chcete zmeniť orientáciu na horizontálnu a určiť počet riadkov, môžete to urobiť takto:


gridLayoutManager.orientation = GridLayoutManager.HORIZONTAL
// Uvedený počet riadkov je len príklad
gridLayoutManager.spanCount = 2
        

Rozdiely medzi LinearLayoutManager a GridLayoutManager

  • Usporiadanie: LinearLayoutManager usporiada položky vertikálne alebo horizontálne v jednom stĺpci alebo riadku. Na druhej strane, GridLayoutManager môže usporiadať položky vo viacerých stĺpcoch alebo riadkoch.
  • Vzhľad: Ak chcete zobraziť položky v klasickom zozname, použite LinearLayoutManager. Ak chcete zobraziť položky v mriežkovom formáte, použite GridLayoutManager.
  • Flexibilita: GridLayoutManager je flexibilnejší v tom, že umožňuje zobrazenie položiek v mriežke s rôznym počtom stĺpcov alebo riadkov v závislosti od orientácie.

Vyberanie medzi LinearLayoutManager a GridLayoutManager závisí od špecifických potrieb vašej aplikácie a typu dát, ktoré chcete zobraziť. Zatiaľ čo LinearLayoutManager je jednoduchší a ľahší na implementáciu, GridLayoutManager poskytuje väčšiu vizuálnu flexibilitu a je lepší pre komplexnejšie rozvrhnutia.

Krok 5: Naplnenie dát do RecyclerView

Naplnenie dát do RecyclerView je jednoduché prostredníctvom adaptéra. Pridajte dáta do zoznamu a oznámte zmeny adaptéru:

myAdapter.updateItems(newData)
        

Aktualizácia zoznamu dát vo vašej aplikácii je bežnou požiadavkou, keď dáta podliehajú zmene alebo sú dynamicky načítané. V RecyclerView v Androide môžeme aktualizovať adaptér s novými položkami pomocou metódy, ako je myAdapter.updateItems(newData). Tu je podrobný opis tohto procesu:

  • Definícia Metódy: V našom adaptéri RecyclerView definujeme metódu updateItems, ktorá prijíma zoznam nových dát. Táto metóda nahradí staré dáta novými.
  • Nahradenie Dát: V metóde updateItems nastavíme aktuálne dáta adaptéra na nový zoznam, ktorý je prenesený ako parameter. Toto prepíše existujúce dáta.
  • Notifikácia o Zmene Dát: Po aktualizácii dát je dôležité zavolať metódu notifyDataSetChanged(), aby bol adaptér informovaný o zmene dát a aby mohol obnoviť zobrazené položky.
  • Vizualizácia Aktualizácií: Keď je metóda notifyDataSetChanged() zavolaná, RecyclerView znovu vyvolá metódu onBindViewHolder pre položky, ktoré sú viditeľné, čím sa aktualizuje obsah zobrazený užívateľovi.
  • Optimalizácia Výkonu: Metóda notifyDataSetChanged() môže byť náročná na výkon, pretože spôsobuje prekreslenie všetkých položiek v RecyclerView. Na optimalizáciu výkonu môžete použiť metódy, ako sú notifyItemInserted(), notifyItemRemoved(), atď., ktoré oznámia zmene iba konkrétnych položiek.

Metóda updateItems(newData) je esenciálna pre udržanie údajov v RecyclerView aktuálnymi. Správna implementácia tejto metódy a efektívne oznámenie zmien adaptéru zabezpečia hladkú a reaktívnu užívateľskú skúsenosť.

Metódy `notifyDataSetChanged()` a ich variácie

1. notifyDataSetChanged()

Informuje `RecyclerView` o tom, že sa zmenili údaje v celom datasete a môže spôsobiť znovu vykreslenie celého zoznamu. Táto metóda je považovaná za výkonnostne náročnú, pretože môže invalidovať všetky položky a znovu ich vykresliť, aj keď sa zmenila iba jedna položka.

2. notifyItemChanged(int position)

Táto metóda informuje `RecyclerView` o zmene v jednej položke na špecifikovanej pozícii. Je efektívnejšia ako `notifyDataSetChanged()`, pretože aktualizuje iba danú položku, a nie celý zoznam.

3. notifyItemInserted(int position)

Informuje `RecyclerView` o tom, že bola na špecifikovanej pozícii vložená nová položka. Používa sa, keď chceme pridať novú položku do datasetu.

4. notifyItemRemoved(int position)

Informuje `RecyclerView` o tom, že položka na špecifikovanej pozícii bola odstránená. Používa sa, keď chceme odstrániť položku z datasetu.

5. notifyItemRangeChanged(int positionStart, int itemCount)

Táto metóda informuje `RecyclerView` o zmene v určenom rozsahu položiek. Je užitočná, keď sa naraz mení viac položiek.

Význam a využitie

Metódy `notify...` sú dôležité pre správnu aktualizáciu zobrazenia v `RecyclerView` po zmene údajov. Zabezpečujú, že používateľ vidí aktuálne údaje a zároveň optimalizujú výkonnosť tým, že obmedzujú vykresľovanie iba na zmenené položky. Odporúča sa vždy používať najšpecifikovanejšiu metódu, ktorá najlepšie zodpovedá zmene v údajoch, aby sa predišlo zbytočnému vykresľovaniu a zlepšila sa výkonnosť aplikácie.

6. Použitie DiffUtil.ItemCallback s RecyclerView.Adapter pre optimalizované aktualizácie zoznamu

Pre tých, ktorí chcú optimalizovať aktualizácie zoznamu v `RecyclerView.Adapter`, je možné použiť `DiffUtil`. Táto trieda vypočíta rozdiely medzi starým a novým zoznamom a automaticky aktualizuje adaptér s príslušnými animáciami.

DiffUtil je nástroj v knižnici RecyclerView, ktorý pomáha optimalizovať aktualizáciu dát v adaptéri zlepšením výkonu a efektívnosti. Konkrétne DiffUtil.ItemCallback sa používa na porovnanie položiek v zozname a identifikáciu zmien, ktoré treba aplikovať. Tu je podrobný opis, ako to funguje s ilustračným kódom:

  • Vytvorenie DiffCallback: Vytvoríme triedu, ktorá rozširuje DiffUtil.Callback, ako je ukázané vo MyItemDiffCallback. Táto trieda definuje logiku porovnávania položiek.
  • Metódy Porovnávania: Implementujeme metódy getOldListSize, getNewListSize, areItemsTheSame a areContentsTheSame pre porovnanie starej a novej kolekcie položiek.
  • Vypočítanie Rozdielov: Používame DiffUtil.calculateDiff na vypočítanie najefektívnejšieho súboru operácií, ktoré prevedú starý zoznam na nový.
  • Aktualizácia Adaptéra: Po vypočítaní rozdielov aktualizujeme dáta v adaptéri a použijeme dispatchUpdatesTo na aplikovanie týchto zmien na adaptér.

Vďaka použitiu DiffUtil, adaptér vie presne, ktoré položky boli pridané, odstránené, alebo zmenené. To znižuje množstvo zbytočných operácií a zlepšuje výkon zobrazenia zoznamu, čím sa zároveň zvyšuje hladkosť a reaktívnosť užívateľského rozhrania.

  • areItemsTheSame: Táto metóda kontroluje, či sú dve položky rovnaké. Je to prvý krok pri porovnávaní dvoch objektov. Metóda porovnáva, či je identifikátor alebo nejaký iný jedinečný ukazovateľ rovnaký pre oba objekty. Ak sú identifikátory rovnaké, znamená to, že ide o rovnakú položku.
  • areContentsTheSame: Ak metóda areItemsTheSame vráti true, DiffUtil potom volá areContentsTheSame, aby zistil, či majú rovnaké položky aj rovnaké údaje. Táto metóda skúma, či sa obsah položiek zmenil. Ak sa obsah nezmenil, metóda by mala vrátiť true; v opačnom prípade vráti false.

V praxi, areItemsTheSame môže porovnávať identifikátory (alebo niektoré ine unikátne kľúče) položiek, zatiaľ čo areContentsTheSame môže porovnávať skutočný obsah. To umožňuje DiffUtil efektívne identifikovať a spracovať pridané, odstránené alebo zmenené položky.

Príklad použitia `DiffUtil` v `RecyclerView.Adapter`:

class MyAdapter : RecyclerView.Adapter<MyViewHolder>() {
    private var items: List<MyItem> = listOf()

    fun updateItems(newItems: List<MyItem>) {
        val diffCallback = MyItemDiffCallback(items, newItems)
        val diffResult = DiffUtil.calculateDiff(diffCallback)
        
        items = newItems
        diffResult.dispatchUpdatesTo(this)
    }

    // ... Zvyšok vášho kódu adaptéra ...
}

class MyItemDiffCallback(
    private val oldList: List<MyItem>, 
    private val newList: List<MyItem>
) : DiffUtil.Callback() {
    override fun getOldListSize() = oldList.size
    override fun getNewListSize() = newList.size
    override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        return oldList[oldItemPosition].id == newList[newItemPosition].id
    }
    override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        return oldList[oldItemPosition] == newList[newItemPosition]
    }
}
        

Použitím `DiffUtil`, môžete získať výhody automatických animácií a optimalizovaných aktualizácií, aj keď používate štandardný `RecyclerView.Adapter` namiesto `ListAdapter`.

Nezabudnite, ze je nevyhnutne upravit aj triedu MyItem v adaptri.

data class MyItem(val id: Int, val imageResource: Int, val text: String) {
    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (javaClass != other?.javaClass) return false

        other as MyItem

        if (id != other.id) return false
        if (imageResource != other.imageResource) return false
        if (text != other.text) return false

        return true
    }

    override fun hashCode(): Int {
        var result = id
        result = 31 * result + imageResource
        result = 31 * result + text.hashCode()
        return result
    }
}

Odporúčané linky

Najmä tieto Codelaby: