IT rekvalifikácia. Seniorní programátori zarábajú až 6 000 €/mesiac a rekvalifikácia je prvým krokom. Zisti, ako na to!

5. diel - Zoznámenie sa s dôležitým komponentom TableView

V minulej lekcii, Jednoduchá kalkulačka pre iOS vo Swift , sme si upevnili vedomosti Autolayout a StackView na jednoduchých ukážkach použitia. StackView skladalo komponenty pod seba alebo sme si u neho mohli nastaviť aj vodorovný smer. V dnešnom Swift tutoriálu sa budeme venovať TableView. Je totiž základom hŕbu aplikácií a pravdepodobne sa mu nevyhnete. Či už si otvoríte aplikáciu pre správy, volania, poznámky a hromadu ďalších, pozeráte sa v prvom rade na TableView.

TableView je ideálny spôsob, ako užívateľovi prezentovať veľa dát alebo ak chcete ich kolekciu. Môže to byť zoznam úloh, kontaktov, hudobných albumov a pod. Práve v takýchto prípadoch je TableView jasná voľba. Umožní vám ľahko zobraziť prakticky neobmedzene prvkov či objektov pekne pod sebou a vyriešiť scrollovanie či ich výber. Veľmi ľahko tiež urobíte mazanie.

Vytvorenie projektu

Teória by mohla pre úvod stačiť a poďme si rovno ukázať jednoduchý spôsob, ako s TableView začať. Pripravte si buď zbrusu nový Xcode projekt s iOS aplikácií (Single View App) alebo použite ten z minulých lekcií.

Teraz si nájdite TableView (nie Table View Controller, k nemu sa ešte dostaneme) v knižnici objektov a pretiahnite ho na váš controller umiestnený v Main.storyboard. Ideálne nastavte constraints, ktoré môžu byť v tomto prípade 0 od všetkých štyroch strán.

Table view v Xcode pre iOS vo Swift - Vyvíjame iOS aplikácia vo Swift

TableView teda máme, ako v ňom zobraziť údaje? Na to bude potrebné zavítať do kódu a to konkrétne do súboru ViewController.swift. Najskôr musíme určiť, že tento controller slúži ako zdroj údajov a delegát pre TableView.

V našom Controlleru implementujeme nasledujúce dva protokoly:

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

To však nestačí. Teraz musíme pridanému TableView nastaviť, že náš controller je jeho DataSource a tiež Delegate. To aby sme mohli vybrať zdroj údajov a tiež reagovať na udalosti, ako je výber riadku (respektíve bunky Cell v reči iOS). Môžeme si dokonca vybrať, ako toto vykonať.

Prepojenie TableView s controllerom pomocou myši

Prvou možnosťou je DataSource a Delegate nastaviť priamo v UI dizajnérov, kedy váš označený TableView pretiahnete za držanie Ctrl alebo pravým klikom na ViewController a vyberiete dataSource. To isté platí pre delegate. Alebo kliknete pravým na TableView v zozname komponentov a pretiahnete dataSource a delegate odtiaľ.

Nastavenie datasource a delegate TableView - Vyvíjame iOS aplikácia vo Swift

Týmto sme vlastne TableView povedali, že náš controller bude reagovať na udalosti TableView a zároveň poskytovať dáta. Vďaka tomu nás tak TableView komponenta môže upozorniť, že používateľ zvolil nejakú položku alebo vykonal ďalšiu akciu.

Prepojenie TableView s controllerom pomocou kódu

Druhou možnosťou je DataSource a Delegate nastaviť v kóde v metóde viewDidLoad(). Osobne preferujem tento spôsob, prepojenie mám na očiach a vždy tak viem, že som na to nezabudol. Kedykoľvek vám u TableView nebude niečo fungovať, skontrolujte najskôr, že ho máte správne prepojené.

Najskôr musíte vášmu TableView vytvoriť Outlet, čo sme prebrali už v minulých lekciách. Potom len nastavíte vašu triedu (teda controller) ako dataSource a delegate.

override func viewDidLoad() {
    super.viewDidLoad()

    tableView.dataSource = self
    tableView.delegate = self
}

Nevyhnutné prípravy máme za sebou a teraz konečne v TableView niečo zobrazíme.

Implementácia protokolov

Aktuálne vám nebude fungovať Build, pretože sme určili, že naša trieda bude implementovať danej protokoly, ale žiadny kód sme do nej zatiaľ nepridali. Teraz sa očakáva, že naša trieda zvládne TableView poskytnúť dáta. Pre začiatok stačí pridať dve metódy:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

}

Prvá metóda vracia koľko budeme mať riadkov. Zatiaľ si prácu nebudeme komplikovať viac sekciami. Druhá má potom na starosť vrátiť danú bunku podľa indexu riadky (respektíve bunky).

Pretože je začiatok funkcií rovnaký, v prípade prvej začnite písať numberOfRowsIn.. a Xcode vám samo doplní správnu metódu. Práve k tomuto slúži dvojaký názvy parametrov. Ten prvý slúži na identifikáciu metódy "zvonku" a druhý používate v tele metódy. Rovnako tak si nechajte doplniť druhú metódu tak, že začnete písať cellForRow...

Príprava dát

Vytvoríme si jednoduché pole, ktoré bude reprezentovať položky to-do listu. Býva zvykom premenné a konštanty deklarovať hneď pod názvom triedy.

var todos = ["Buy coffee", "Take out the trash", "Netflix and chill"]

Je úplne jedno, čo sem napíšete. Cieľom je mať akékoľvek pole s nejakými hodnotami, ktoré si v našom TableView zobrazíme. Teraz upravíme naše dve metódy.

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return todos.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = UITableViewCell()
    cell.textLabel?.text = todos[indexPath.row]
    return cell
}

Nič zložité. Prvá metóda vracia počet prvkov a druhá vytvára bunku a nastavuje jej text podľa jej indexu. Texty sa ťahajú z nášho poľa. Aplikáciu môžete spustiť a uvidíte všetky prvky vášho poľa pod sebou.

TODO list v Xcode a Swift - Vyvíjame iOS aplikácia vo Swift

TableView pod pokrievkou

Zároveň si zapamätajte, že takto by metóda s cellForRowAt nemala nikdy vyzerať. Chcel som len čo najrýchlejšie ukázať funkčné TableView. Teraz si povieme ako TableView funguje "pod pokrievkou".

Scrollovanie položkami bude veľmi plynulé aj v prípade stovky buniek. TableView je totiž múdra komponenta a drží iba bunky, ktoré je nutné zobraziť na displeji. Jednoducho môžeme povedať, že bunky recykluje, k čomu je potrebné dôležitá metóda:

let recycledCell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)

Tieto metódy sú v skutočnosti dve, druhá nemá druhý parameter a nikdy by ste ju nemali používať. Jedná sa o starú verziu, ktorá zostala zachovaná kvôli spätnej kompatibilite.

Možno ste zbystrili parameter withIdentifier, ktorý musíme nastaviť, aby všetko fungovalo. Pred použitím ale musíme ešte pripraviť TableView. Otvorte designer a po vybraní komponenty nastavte v Attributes inspector hodnotu pre Prototype Cells na 1.

Nastavenie Prototype Cells TableView v Xcode - Vyvíjame iOS aplikácia vo Swift

Následne je potrebné vybrať túto prototyp bunku, ktorá sa objaví v náhľade. Kliknúť môžete priamo v náhľade alebo ju vybrať v zozname komponentov tohto Controlleru naľavo.

Výber prototyp bunky v TableView - Vyvíjame iOS aplikácia vo Swift

Potom stačí opäť v Attributes inspector nastaviť Identifier na "cell", ktorý máme už v kóde vyššie. Môžete si samozrejme zvoliť čokoľvek iného.

TableView Attribute inspector v Xcode - Vyvíjame iOS aplikácia vo Swift

Teraz stačí aplikáciu spustiť a mali by ste opäť vidieť svoje to-do.

A prečo celá tá práca? Týmto sme správne použili TableView a naša komponenta je pripravená pokojne na zobrazovanie stoviek riadkov. V skutočnosti totiž vždy existujú iba tie, ktoré sú vidieť na displeji, takže veľký počet dát nespomalí aplikáciu. V tomto prípade nás to určite trápiť nemusí, ale ukázali sme si korektné riešenie.

Je tu tiež druhý benefit. Sme na dobrej ceste k vytvoreniu komplexnejšiu bunky, respektíve riadku TableView. Práve to nám naše Prototype Cell umožňuje. Jednoducho by sme na nej presunuli požadované komponenty a vytvorili špeciálnu triedu. To si ukážeme v neskorších lekciách kurze.

Výber a mazanie položiek

Teraz si ukážeme, ako v TableView vyberať a tiež mazať jednotlivé položky.

Vybranie položky

Pre situáciu, kedy užívateľ vyberie položku, tu máme pripravenú metódu:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {   }

Opäť môžete začať písať iba didSelect... a Xcode vám metódu ponúkne a samo vytvorí. Zatiaľ nebudeme po vybraní riadku robiť nič extra, len si vypíšeme (do Output okna v Xcode) zvolený text, v našom prípade teda zvolenej to-do.

Metódu doplníme o volanie funkcie print(). Z parametra indexPath si cez vlastnosť row zistíme, aký riadok bol vlastne vybraný, a ten použijeme ako index pre naše todos[] pole.

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    print(todos[indexPath.row])
}

Po výbere riadku sa vám teraz vypíše vybrané to-do do konzoly. Ešte vyriešime mazanie a tým zatiaľ zoznámenie s TableView ukončíme.

Odstránenie položky

Na mazanie položiek tu opäť máme pripravenú metódu:

func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {  }

Pridaním tejto metódy vlastne dávame najavo, že chceme TableView modifikovať. Teraz sme už v stave, kedy sa vám pri swipe geste doľava zobrazí tlačidlo Delete pri jednotlivých riadkov. Zatiaľ ale nebude fungovať.

Pomocou parametra editingStyle si v tele metódy zistíme, či ide o mazanie a ak áno, tak tento prvok zmažeme. Najskôr z nášho zdrojového poľa todos[] a následne ešte z TableView, kde si môžeme vybrať animáciu. Kód potom vyzerá nasledovne.

func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
    if editingStyle == .delete {
        todos.remove(at: indexPath.row)
        tableView.deleteRows(at: [indexPath], with: .fade)
    }
}

Animáciu si môžete vybrať podľa seba, často sa pre zjednodušenie a konzistenciu používa voľba .automatic.

TableView staticky

Na záver úvodného zoznámenie si ukážeme, ako vytvoriť TableView, keď presne vieme, čo budeme mať za bunky, prípadne rovno sekcie. Jedná sa teda napr. O nejakej menu a inú situáciu, ako keď položky čítame z nejakej kolekcie. Tento spôsob sa skvele hodí, ak chceme ponúknuť v aplikácii komplexnejšie možnosti nastavenia, aby sme sa priblížili systému iOS, kde je v nastavení zariadenia TableView na každom kroku.

Pretiahnite si do projektu Table View Controller, ktorý je potrebné pre statický TableView. Potom stačí TableView označiť a v Attributes inšpektorovi nastaviť Content na Static Cells. Následne si môžete vybrať počet sekcií. Každá môže mať vlastný nadpis a tiež pätičku. Jednotlivé sekcie potom stačí označiť a všetko potrebné nastaviť, vrátane jednotlivých riadkov.

Nastavenie sekcií statického TableView v Xcode - Vyvíjame iOS aplikácia vo Swift

Jednotlivé bunky nemusí byť iba riadok textu. Pre každú môžete zvlášť nastaviť Style a mať napr. Text + podtitulok, pridať obrázok a tak podobne. Často sa nastavuje tiež vlastnosť Accessory (opäť v Attributes inšpektor), ktorá v ľavej časti bunky zobrazí napr. Šípku a tým užívateľovi naznačí, že voľba vedie na ďalšiu obrazovku a tak podobne.

Sekcia v statickom TableView v Xcode - Vyvíjame iOS aplikácia vo Swift

Pre náš nový controller potrebujeme ešte triedu. Pridáme súbor, ale v dialógu namiesto Swift file vyberieme Cocoa Touch Class. V novom dialógu nastavíme, že ide o subclass UITableViewController a pomenujeme ho napr. SettingsTableViewController. Teraz už len stačí v Main.storyboard vybrať náš nový TableViewController a v Identity inspector mu nastaviť Class na novovytvorenú triedu SettingsTableViewController.

Vyvíjame iOS aplikácia vo Swift

Statický TableView zakončíme reakciou na výber bunky. V SettingsTableViewController nemusíme riešiť DataSource ani Delegate, pretože to všetko rieši trieda UITableViewController. Stačí nám tak len implementovať didSelectRowAt metódu. Iba pred ňou potrebujeme override, aby sme mohli poskytnúť vlastnú implementáciu.

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    print("Selected row \(indexPath.row) in section \(indexPath.section)")
}

Opäť bude stačiť výpis pre kontrolu. V skutočnej implementácii by sa celkom hodil switch (jedno z mála miest, kde má zmysel), zvlášť, ak by ste mali veľa sekcií a riadkov. V tejto metóde by mohol napríklad switch riešiť len sekcie a jednotlivé sekcie by mali vlastné metódy v štýle handleFirstSection(row: Int) a tak ďalej. Mohol by vyzerať napr. Nasledovne:

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    print("Selected row \(indexPath.row) in section \(indexPath.section)")

    switch indexPath.section {
        case 0:
            handleFirstSection(rowIndex: indexPath.row)
        case 1:
            handleSecondSection(rowIndex: indexPath.row)
        default:
            break
    }
}

func handleFirstSection(rowIndex: Int) {
    switch rowIndex {
        case 0:
            // Show account detail
            break
        case 1:
            // Navigate to settings
            break
        default:
            break
    }
}

func handleSecondSection(rowIndex: Int) {

}

Týmto naše úvodné zoznámenie s TableView komponentom končí. V nasledujúcich lekciách tieto znalosti využijeme pre vytvorenie skutočnej TODO aplikácie vrátane databázy. Nabudúce, v lekcii Neobjavujte koleso, použite CocoaPods , sa naučíme používať CocoaPods, ktorý nám umožní využívať balíčkovací systém a jednoduchú inštaláciu rôznych knižníc.


 

Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.

Stiahnuť

Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami

Stiahnuté 60x (82.88 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Swift

 

Predchádzajúci článok
Jednoduchá kalkulačka pre iOS vo Swift
Všetky články v sekcii
Vyvíjame iOS aplikácia vo Swift
Preskočiť článok
(neodporúčame)
Neobjavujte koleso, použite CocoaPods
Článok pre vás napísal Filip Němeček
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
Autor se věnuje vývoji iOS aplikací (občas macOS)
Aktivity