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.
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ľ.
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.
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
.
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.
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.
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.
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.
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
.
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