Fotografický magazín "iZIN IDIF" každý týden ve Vašem e-mailu.
Co nového ve světě fotografie!
Zadejte Vaši e-mailovou adresu:
Kamarád fotí rád?
Přihlas ho k odběru fotomagazínu!
Zadejte e-mailovou adresu kamaráda:
Software
Programování pro iOS - 42. UISplitViewController
18. května 2011, 00.00 | Dříve, než se pustíme do podrobného výkladu služeb, možností, výhod a také nedostatků a nedomyšleností nového vývojového prostředí Xcode 4, dokočíme naši současnou sekci věnovanou řídicím objektům rámců. Moc nám toho zde již nezbývá.
Moc nám toho zde již nezbývá, pokud si dovolíme velmi specializované případy (třeba takový UIImagePickerController nebo UIVideoEditorController) přeskočit. Dnes se podíváme blíž na UISplitViewController. Základní princip funkce třídy UISplitViewController je velmi jednoduchý a z uživatelského hlediska jej důvěrně známe z řady standardních aplikací – využívá jej kupříkladu Mobile Mail.
Podobně jako ostatní řídicí objekty rámců, jimiž jsme se zabývali v poslední době, je i UISplitViewController "kontejnerem", který obsahuje jiné řídicí objekty a stará se o jejich zobrazování. Ačkoli API, jež nabízí přístup k těmto vnořených řídicím objektům je nám již dávno známé obecné pole
@property(nonatomic, copy) NSArray *viewControllers;
tentokrát jsou možnosti pro jeho obsah přísně omezeny: musí vždy obsahovat právě dva řídicí objekty rámců. Prvý z nich by měl vždy obsahovat nějaký "obsah" – v praxi je jím téměř vždy tabulka, jež zobrazuje možné volby v nějakém seznamu. Druhý z nich pak je tímto obsahem řízen, a standardně zobrazuje detailní informace o volbě, vybrané v tom prvém.
Třída UISplitViewController se pak stará o správné zobrazení obou řídicích objektů:
• je-li iPad – stejně jako "popovery", i "split view" je určeno výhradně pro něj – v horisontální poloze, zobrazí se rámce obou řídicích objektů vedle sebe. Ten prvý v poněkud užším sloupci, ten druhý pak zabere celý zbytek obrazovky;
• je-li naproti tomu iPad ve vertikální poloze, rámce prvého řídicího objektu jsou skryty, a vidět je pouze ten druhý. Předpokládá se, že pro dočasné zobrazení toho prvého a "výběr z obsahu" bude použit popover (sám aktivovaný stisknutím tlačítka v příkazové liště) – a třída UISplitViewController k tomu nabízí poměrně pohodlnou podporu.
Naopak pro komunikaci mezi hlavním "obsahovým" a podřízeným "detailním" řídicím objektem nenabízí podporu žádnou; to je čistě věcí programátora. Velmi často se k tomu využívá mechanismu delegace; my si zde ukážeme alternativní, poněkud flexibilnější přístup, založený na notifikacích.
Pojďme si přidat "split view" do naší aplikace!
Jelikož v minulých dílech našeho seriálu jsme umístili popovery do "SecondViewControlleru", použijeme nyní pro praktickou ukázku "split view" dosud nedotčený řídicí objekt prvé záložky, FirstViewController. Bude zapotřebí, abychom postupně implementovali následující kroky:
a) sestavíme řídicí objekt pro hlavní "obsah"; použijeme k tomu dávno známý UTableViewController;
b) upravíme FirstViewController tak, aby tomuto obsahu mohl sloužit jako podřízený kontrolér pro zobrazování detailů;
c) postaráme se o komunikaci mezi nimi;
d) zajistíme, aby do "tab baru" – který, jak si jistě vzpomínáte, tvoří základní kostru naší aplikace – byl namísto FirstViewControlleru uložen řídicí objekt třídy UISplitViewController, obsahující oba naše řídicí objekty;
e) a nakonec ještě doplníme podporu pro "toolbar" a tlačítko, otvírající "popover" s obsahem je-li zařízení postaveno na výšku.
Jak hned uvidíme, není to nijak obtížné; s výjimkou bodu (d), v němž se dopustíme určité "prasárny", abychom si trochu usnadnili práci, proto tentokrát věnujeme nějaký čas i tomu, abychom programovali čistě a korektně :)
Řídicí objekt tabulky
Tohle už je pro nás určitě dávno "stará vesta": následující kód můžeme uložit rovnou na začátek zdrojového souboru "FirstViewController.m", nebo – chceme-li – do samostatných zdrojových souborů (pak samozřejmě bude zapotřebí ten s rozhraním do souboru "FirstViewController.m" importovat).
Obsahuje nejjednodušší možnou tabulku s fixním obsahem a s odesláním notifikace po zvolení některého z řádků. Navíc je zde pouze ještě metoda shouldAutorotateToInterfaceOrientation:, jež zajistí, aby bylo možno tabulku zobrazit v kterékoli orientaci zařízení:
@interface FixedTableVC:UITableViewController {
NSArray *items;
}
@end
@implementation FixedTableVC
-(NSInteger)tableView:(UITableView*)tv
numberOfRowsInSection:(NSInteger)section {
if (!items) items=[[NSArray alloc] initWithObjects:
@".223 Remington",
@".380 Winchester",
@".408 CheyTac",
@".50 BMG",nil];
return items.count;
}
-(UITableViewCell*)tableView:(UITableView*)tv
cellForRowAtIndexPath:(NSIndexPath*)ip {
UITableViewCell *cell=
[tv dequeueReusableCellWithIdentifier:@"0"];
if (!cell)
cell=[[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:@"0"]
autorelease];
cell.textLabel.text=[items objectAtIndex:ip.row];
return cell;
}
-(void)tableView:(UITableView*)tv
didSelectRowAtIndexPath:(NSIndexPath*)ip {
[[NSNotificationCenter defaultCenter]
postNotificationName:@"Selected"
object:[items objectAtIndex:ip.row]];
}
-(BOOL)shouldAutorotateToInterfaceOrientation:
(UIInterfaceOrientation)io {
return YES;
}
@end
Příjem a zobrazování detailů ve FirstViewControlleru
Podíváme-li se do souboru "FirstView.xib", který nám připravil projektový vzor Xcode, uvidíme, že zde je textové pole UIlabel a dokonce při horním okraji rámce i "toolbar". Ty budeme moci oba přímo využít.Začneme tedy tím, že si připravíme "outlety" pro přístup k nim (v tomto kroku budeme potřebovat pouze "label"; při jednom si ale připravíme odkaz na "toolbar", který využijeme až nakonec).
Slíbili jsme si, že dnes budeme psát poctivě a nebudeme ignorovat nebezpečí "memory leaků"; namísto prostých instančních proměnných, jež by, jak víme, objekty GUI automaticky "retainovali", si připravíme "outlety" jako atributy typu assign – to zajistí, že při jejich vyplnění nebude retain použit. Bylo by to samozřejmě zbytečné: objekty GUI drží při životě sám kořenový rámec (a ten je automaticky "retainován" ve zděděném atributu view):
@interface FirstViewController:UIViewController
@property (assign,nonatomic) IBOutlet UILabel *label;
@property (assign,nonatomic) IBOutlet UIToolbar *toolbar;
@end
Pak otevřeme XIB a "nataháme dráty" pro správné propojení objektů GUI s nově vytvořenými "outlety" – to už si dnes snad opravdu obrázkem ilustrovat nemusíme :)
V implementaci pak přidáme do vhodné standardní metody – dobře se na to hodí viewDidLoad – registraci pro příjem notifikace, kterou tabulka prvého řídicího objektu posílá, a hned použijeme "outlet" label pro zobrazení jejího obsahu:
-(void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(didSelect:)
name:@"Selected" object:nil];
}
-(void)didSelect:(NSNotification*)nn {
label.text=nn.object;
}
Je ovšem zapotřebí ještě korektně vyprázdnit odkazy na objekty GUI v případě, že je hlavní rámec (který je obsahuje) uvolněn; zároveň se v takovém případě můžeme odhlásit od příjmu notifikací:
-(void)viewDidUnload {
[super viewDidUnload];
[[NSNotificationCenter defaultCenter] removeObserver:self];
label=nil;
toolbar=nil;
}
Vnucení UISplitView do "tab baru"
V tomto kroku si dovolíme trochu "podraz" – ušetříme si tím práci. Pokud bychom aplikaci teprve sestavovali, samozřejmě správným řešením by bylo do "tab baru" umístit přímo řídicí objekt třídy UISplitViewController; ten bychom patřičným způsobem inicializovali, a nikde by žádný problém nebyl.My ovšem již máme hotovou strukturu, kde "tab bar" obsahuje přímo náš "FirstViewController". Abychom si ušetřili práci s jejím předěláváním, prostě dynamicky strukturu aplikace změníme z kódu ve chvíli, kdy se náš řídicí objekt načte – dále tedy upravíme metodu viewDidLoad, aby vypadala takto:
-(void)viewDidLoad {
[super viewDidLoad];
UITabBarController *tbc=self.tabBarController;
NSArray *a=tbc.viewControllers;
unsigned n=[a indexOfObjectIdenticalTo:self];
if (n!=NSNotFound) {
UISplitViewController *svc=
[[UISplitViewController alloc] init];
svc.viewControllers=[NSArray arrayWithObjects:
[[[FixedTableVC alloc] init] autorelease],
self,
nil];
NSMutableArray *ma=[a mutableCopy];
[ma replaceObjectAtIndex:n withObject:svc];
[tbc performSelector:@selector(setViewControllers:)
withObject:ma
afterDelay:0];
}
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(didSelect:)
name:@"Selected" object:nil];
}
Smysl přidaného kódu je asi zřejmý: pokud zjistíme, že náš řídicí objekt je dosud součástí "tab baru", vytvoříme nový UISplitViewController a také nový řídicí objekt "obsahové" tabulky FixedTableVC. Do "split view" uložíme řídicí objekt tabulky a řídicí objekt FirstViewController. Pak pošleme "tab baru" odloženou zprávu setViewControllers:, v níž mu namísto FirstViewControlleru vnutíme právě nově vytvořený UISplitViewController.
Nyní již můžeme aplikaci vyzkoušet; bude fungovat dobře v té míře, že v horizontálním režimu uvidíme vedle sebe oba řídicí objekty a volba řádku v tabulce zobrazí jeho obsah ve FirstViewControlleru:
Ve vertikální poloze ale zatím zůstává toolbar prázdný; musíme se ještě nějak postarat o vložení a aktivaci odpovídajícího tlačítka. Naopak o vytvoření a otevření "popoveru" se starat nemusíme; to za nás provede knihovní kód.
Podpora toolbaru
API, jež třída UISplitViewController nabízí pro podporu práce s "toolbarem", je pohodlné, ačkoli na první pohled poněkud netypické. Zkušený programátor by patrně očekával, že třída UISplitViewController bude obsahovat metodu pro otevření "popoveru"; není tomu ale tak. Místo toho nám v metodě delegáta přidá rovnou připravené tlačítko, jež obsahuje adekvátní "akci" i "cíl"; my už jen musíme zkonfigurovat jeho vzhled a do "toolbaru" je vložit – využijeme zde "outletu", který jsme si připravili dříve spolu s "labelem":
-(void)splitViewController:(UISplitViewController*)svc
willHideViewController:(UIViewController*)vc
withBarButtonItem:(UIBarButtonItem*)bbi
forPopoverController:(UIPopoverController*)poc {
bbi.title=@"Select...";
[toolbar setItems:[NSArray arrayWithObject:bbi] animated:YES];
}
Druhá metoda delegáta nás pak informuje o tom, že je vhodné tlačítko z "toolbaru" opět odstranit:
-(void)splitViewController:(UISplitViewController*)svc
willShowViewController:(UIViewController*)vc
invalidatingBarButtonItem:(UIBarButtonItem*)bbi {
[toolbar setItems:[NSArray array] animated:YES];
}
Nakonec ovšem nesmíme zapomenout na to, abychom náš řídicí objekt nastavili pro "split view" jako delegáta, abychom adekvátní zprávy vůbec dostávali (a v rozhraní uvedeme, že třída FirstViewController odpovídá protokolu UISplitViewControllerDelegate):
-(void)viewDidLoad {
...
[tbc performSelector:@selector(setViewControllers:)
withObject:ma
afterDelay:0];
svc.delegate=self;
}
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(didSelect:)
name:@"Selected" object:nil];
}
– a to je vše, tím jsme hotovi:
Obsah seriálu (více o seriálu):
- Nastal čas na kakao...
- Tak nejdřív kakao ochutnáme...
- Programovací jazyk C: velmi, velmi stručně
- Objective C: to si vysvětlíme podrobněji
- Co jsme si o Objective C ještě neřekli...
- Nastal čas na kakao - Vznik a zánik objektů
- Nastal čas na kakao - Kopírování objektů
- Nastal čas na kakao - Skryté podtřídy
- Nastal čas na kakao - Základní služby objektů
- Nastal čas na kakao - Jak správně psát v Objective C
- Nastal čas na kakao - Jak správně importovat
- Nastal čas na kakao - Podtřídy, delegáti, vkládání, jak se to rýmuje?
- Nastal čas na kakao - Využití kategorií namísto dědičnosti
- Nastal čas na kakao - Vkládání objektů a přesměrování zpráv
- Nastal čas na kakao - Inicializace a rušení objektů
- Nastal čas na kakao - Metody initWith... a designovaný inicializátor
- Nastal čas na kakao - Inicializace: tipy a triky
- Nastal čas na kakao - Accesory: přístup k proměnným instancí
- Nastal čas na kakao - Šedá je teorie, zelený je strom života...
- Nastal čas na kakao - Více o XCode: inspektory
- Nastal čas na kakao - Aplikace RSS2: datový model
- Nastal čas na kakao - Aplikace RSS: implementace datového modelu
- Nastal čas na kakao - Aplikace RSS: parsování XML
- Nastal čas na kakao - Interface Builder a uživatelské rozhraní
- Nastal čas na kakao - Interface Builder: atributy objektů
- Nastal čas na kakao - Interface Builder: atributy objektů
- Nastal čas na kakao - Druhý kontrolér a dokončení aplikace
- Nastal čas na kakao - Drobná vylepšení a zdokonalení...
- Nastal čas na kakao - Ladění
- Nastal čas na kakao - Třídy Foundation Kitu
- Nastal čas na kakao - Třídy Foundation Kitu (2)
- Nastal čas na kakao - Textové řetězce: NS(Mutable)String
- Nastal čas na kakao - Čísla, binární data a další...
- Nastal čas na kakao - Archivace objektů
- Nastal čas na kakao - Trocha magie, aneb distribuované objekty
- Nastal čas na kakao - Málem bychom zapomněli: NSAutoreleasePool
- Nastal čas na kakao - Zpracování výjimek: NSException
- Nastal čas na kakao - NSInvocation a černá magie
- Nastal čas na kakao - Kakao v Tygrovi
- Nastal čas na kakao - Notifikace: nepřímé předávání zpráv
- Nastal čas na kakao - NSUserDefaults
- Nastal čas na kakao - Co nového ve Foundation Kitu
- Nastal čas na kakao – s Intelem, s Intelem, jedeme do...
- Co nového v Xcode
- Začínáme s AppKitem
- Jak MVC v Kakau vypadá doopravdy?
- Jak MVC v Kakau vypadá doopravdy: dokončení
- Přehled tříd AppKitu
- Nastal čas na kakao - Přehled tříd AppKitu 2
- Přehled tříd AppKitu 3: zbývající třídy GUI
- Přehled tříd AppKitu 4: textový systém
- Nastal čas na kakao - Přehled tříd AppKitu 5: hlavně grafika
- Přehled tříd AppKitu 6: dokumentový systém
- Přehled tříd AppKitu 7: dokončení
- Pojmenované vlastnosti objektů
- Pojmenované vlastnosti objektů: implementace
- Pojmenované vlastnosti objektů: relace 1:N
- Pojmenované vlastnosti objektů: řazení jmen a agregační funkce
- Sledování změn objektů
- Sledování změn objektů – ukázka
- Sledování změn objektů – zdrojový kód
- Sledování změn objektů: kód modelu
- Sledování změn objektů: přímý přístup
- Kontroléry a vazby
- Vázání vazeb
- Další vazby s jednoduchým kontrolérem
- Implementace a použití převodu hodnot
- Validace hodnot
- Validace a chyby, a jedna hezká vazba...
- Práce s polem objektů
- Základní vazby NSArrayControlleru
- Převodníky, přepínače, placeholdery
- Mírná vylepšení v mezích zákona
- Objective C 2.0 - novinky z Leoparda
- NSTreeController
- Programování v Cocoa - Pár tipů a triků
- Programování v Cocoa - Základy kreslení
- Kterak nakreslit modrý obdélník...
- Další služby pro kreslení
- Obrázky a písmenka...
- Události a myš
- Lepší práce s myší
- Události klávesnice
- Input Management
- Příkazy a schránka
- Další události
- Táhni a padni
- Byli jsme na tahu; nyní padneme.
- Zvolme si, jak vhodit
- Drobnosti a chybičky
- Speciální případy tahání či házení
- Kterak táhnout něco, co neexistuje?
- Jak na sítě...
- NSURLConnection
- Safari za minutu
- Služby WebKitu
- Kakao v Leopardu
- Druhé Objective C
- Druhé Objective C: různé drobnosti
- Druhé Objective C: kategorie a protokoly
- Druhé Objective C: nový příkaz cyklu
- Druhé Objective C: atributy a accesory
- Druhé Objective C: atributy a accesory
- 64 je dvakrát 32
- Ubicumque dulce est, ibi et acidum invenies...
- Irbis: že prý žádné novinky?
- Blok sem, blok tam, nám už je to všechno jasné...
- Bloky jsou i v AppKitu
- Irbis a Foundation Kit
- Kde jsou má data?
- Kde jsou má data? V NSCache!
- Soubor, jméno, URL, jak se to rýmuje...
- Další podpora NSURL
- Zabíjení!
- A máme tady i...OS!
- Systémové prvky GUI
- Programování pro iOS 1. díl - Rozdíly mezi "i" a "Mac"
- Programování pro iOS - 2. Začínáme programovat
- Programování pro iOS - 3. základní ovladače a propojení GUI s kódem
- Programování pro iOS - 4. Varovná hlášení
- Programování pro iOS - 5. Rámce a jejich řídicí objekty
- Programování pro iOS - 6. Ukládání dat
- Programování pro iOS - 7. Správa paměti a starý restík
- Programování pro iOS - 8. Dokončení aplikace
- Programování pro iOS - 9. Jak dostat aplikaci do iPhone
- Programování pro iOS - 10. Instalace aplikace do cizího iPhone
- Programování pro iOS - 11. Jak dostat aplikaci do libovolného iPhone
- Programování pro iOS - 12. Touching!
- Programování pro iOS - 13. Kreslíme na iPhone
- Programování pro iOS - 14. Udělejme gesto
- Programování pro iOS - 15. Další gesta
- Programování pro iOS - 16. Více prstů, více zábavy
- Programování pro iOS - 17. Podpora standardních gest
- Programování pro iOS - 18. Recognizery v iOS
- Programování pro iOS - 19. Další standardní recognizery
- Programování pro iOS - 20. Co nového v iOSu
- Programování pro iOS - 21. "Multitasking"
- Programování pro iOS - 22. Nulla est honesta avaritia nisi temporis
- Programování pro iOS - 23. Jak se aktivovat, jsme-li v pozadí
- Programování pro iOS - 24. Zbývající drobnosti
- Programování pro iOS - 25. Řídicí objekty rámců
- Programování pro iOS - 26. Jak se dělá UIViewController
- Programování pro iOS - 27. Kde vzít rámce
- Programování pro iOS - 28. Základní služby
- Programování pro iOS - 29. Práce s rámci
- Programování pro iOS - 30. Rotace zařízení
- Programování pro iOS - 31. Správa paměti v rámcích
- Programování pro iOS - 32. Řídicí objekt pro tabulky
- Programování pro iOS - 33. Řídicí objekt pro strom
- Programování pro iOS - 33. Více o UINavigationControlleru
- Programování pro iOS - 35. Ještě jednou UINavigationController
- Programování pro iOS - 36. Po navigátoru taby
- Programování pro iOS - 37. Více o UITabBarControlleru
- Programování pro iOS - 38. Dokončení UITabBarControlleru
- Programování pro iOS - 39. UIPopoverController
- Programování pro iOS - 40. Další triky UIPopoverControlleru
- Programování pro iOS - 41. Zbývající služby UIPopoverControlleru
- Programování pro iOS - 42. UISplitViewController
- Programujeme v
iTunesXcode 4 - Programování pro iOS - 44. Předvolby Xcode 4
- Programování pro iOS - 45. Práce v Xcode 4
- Xcode 4: projekt a cíle
- Xcode 4: práce s cíli
- Xcode 4: Build Settings
- Xcode 4: Build Phases
- Xcode4: Build Phases podruhé
- Xcode 4: Co jsou to Build Rules?
- Xcode4: taje editoru
- Xcode4: automatické doplňování v editoru
- XIBy chyby
- Více o XIBech
- Editor XIBů
- Inspektory pro XIBy
- Vazby mezi objekty v XIBech
- Vazby mezi objekty v kódu
- Paletky Xcode pro XIBy
- Xcode 4: levý sloupec
- Xcode 4: okno Organizer
- Xcode 4: okno Organizer, část druhá
- Xcode 4: co je to Workspace?
- Xcode 4: základy schémat
- Xcode 4: akční schémata