< Zpět na články

Jak na layout pro tablety s UISplitViewController?

Pokud píšete mobilní aplikace nejen pro iPhony, ale i pro iPady, určitě jste se s nějakým layoutem s UISplitViewControllerem už museli setkat. Na iPhonu máte obrazovku se seznamem prvků a výběrem prvku se prokliknete do jeho detailu – provede se push jako při klasické navigaci. UISplitViewController tabletu využíváme větší obrazovku a to tak, že seznam prvků je vlevo a detail prvku se po výběru ukáže vpravo.

UISplitViewController před/po iOS 14

Před iOS 14 UISplitViewController podporoval pouze výše popsaný “klasický” model
se dvěma obrazovkami – levá jako primary, pravá jako secondary. V iOS 14 přibyla možnost nového UISplitViewController API pro dva/tři sloupce, tím se ale dnes zabývat nebudu. V klasickém modelu inicializaci provedeme pomocí UISplitViewController() (bez parametrů). UISplitViewControlleru nelze nastavit přímo konkrétní mód zobrazení, místo toho definujeme preferovaný mód zobrazení preferredDisplayMode. V klasickém modelu jsou tři základní módy – secondaryOnly (iPhone-like), oneBesideSecondary/oneOverSecondary (iPad-like, rozdíl je v ztmavení pravé části obrazovky v případě oneOverSecondary). Je důležité ale podotknout, že ani jeden z módů není zaručený, na malých obrazovkách například bude vždy použit secondaryOnly.

Jednoduchý layout = ☀️

Pokud implementujete pouze jednoúrovňové menu, je použití UISplitViewControlleru vcelku bezproblémové a jednoduché. Doleva nastavíte obrazovku se seznamem prvků, doprava obrazovku detailu a je vystaráno. UISplitViewController se postará o správné zobrazení – na iPhonu použije NavigationController, na iPadu použije layout se dvěma sloupci a dokonce mezi těmito módy správně přepne například v situaci, kdy dáte na iPadu aplikaci do split módu nebo na iPhonu s větším displejem otočíte telefon naležato.

Trait collection – 💩 #1

Při implementaci mobilních aplikací pro iPhone a iPad se design často liší, například jsou zde použity jiné obrázky, jednotlivé prvky jsou různě odsazené… Jedním z užitečných způsobů, jak design měnit, je pozorováním změn traitCollection (metoda traitCollectionDidChange). Bohužel, trait collection reaguje ne vždy úplně ideálně – například při zobrazení obrazovky pomocí present na začátku vždy pošle traitCollection regular (tablet), a to i na mobilu – to by ale bylo na další blog.

Ve UISplitViewControlleru se na traitCollection jednotlivých ViewControllerů nedá spoléhat – viewController, který je zobrazen vlevo, bude mít totiž vždy traitCollection compact (mobilní), a to i na tabletu. Řešením je používat traitCollection UISplitViewControlleru, ke které se dá dostat přes splitViewController?.traitCollection. Změny pak musíme pozorovat pomocí UISplitViewControllerDelegate a metod splitViewControllerDidCollapse / splitViewControllerDidExpand.

Aby toho nebylo málo, traitCollection se propaguje špatně nejen do view controlleru, ale také do UICollectionCellView. Je tedy vhodné použít configure metodu, které kromě dat předáte i aktuální splitViewController?.traitCollection.

Složitější layout – 💩 #2

Jak jsem popisoval výše, při použití jednoduchého layoutu je práce s UISplitViewControllerem velmi jednoduchá. V mém případě jsem ale potřeboval na iPadu mít vlevo dvouúrovňové menu a na iPhonu jednoúrovňové. Navíc jsem potřeboval mít NavigationController i v detailu, můj layout tedy obsahoval na tabletu vlevo i vpravo NavigationController, zatímco na iPhonu pouze jeden NavigationController.

Při nativním chování se mi při collapsu NavigationControllery vložily do sebe, navíc se přes sebe zobrazily jejich nadpisy. Musel jsem tedy znovu nastavit a resetovat celý UISplitViewController, což jak při collapsu, tak při expanzi obnášelo popnutí všech view controllerů z levého NavigationControlleru a následné znovunačtení.

guard let firstNav = splitViewController.viewControllers.first as?    
                UINavigationController else { return }  
firstNav.popToRootViewController(animated: false) { [weak self] in  
   startView(splitVC: splitViewController, nav: firstNav)  
}

Shrnutí

Jestli potřebujete použít UISplitViewController, použijte (pokud můžete) ten nejjednodušší layout. Pouze nastavíte levý controller, místo navigationController.pushViewController použijete splitViewController.showDetailViewController a UIKit se o zbytek postará za vás. Dělání jakéhokoliv složitějšího layoutu může být hodně složité a časově náročné, ale dá se to – jen musíte vždy používat traitCollection předaného UISplitViewControlleru.

Ondřej Wrzecionko
Ondřej Wrzecionko
iOS Developer

Máte zájem o spolupráci? Pojďme to probrat osobně!

Napište nám >