Programování pro iOS - 37. Více o UITabBarControlleru - MujMAC.cz - Apple, Mac OS X, Apple iPod

Odběr fotomagazínu

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:

Soutěž

Sponzorem soutěže je:

IDIF

 

Jaký fotograf/ka získal/a cenu za nejpopulárnější příspěvek v Nikon Photo Contest?

V dnešní soutěži hrajeme o:

Seriály

Více seriálů



Informace

Programování pro iOS - 37. Více o UITabBarControlleru

13. dubna 2011, 00.00 | Více o UITabBarControlleru: dnes si ukážeme ukládání pořadí "tabů".

Minule jsme se seznámili s třídou UITabBarController a naučili jsme se základy jejího využití; viděli jsme také, že ačkoli tato třída nabízí ještě více standardních služeb než UINavigationController, její API je dokonce malinko jednodušší – zato je více věcí, jež fungují "automaticky a bez jakékoli práce".

Mezi těmito "automatickými" službami je dokonce i kompletní konfigurace "tab baru", tj. stránka, jež uživateli umožní měnit pořadí ikon i rozhodovat, které z ikon jsou přímo v dolní liště, a které jsou dosažitelné prostřednictvím standardního odkazu "Více" u jejího pravého okraje. Zjistili jsme ale, že toto nastavení aplikace "zapomene" po ukončení a novém spuštění; dnes začneme tím, že si ukážeme, jak to napravit.

Služby delegáta

K tomu, abychom mohli snadno zajistit potřebné uložení aktuálního stavu ikon v dolní liště, potřebujeme informaci o tom, že jej případně uživatel změnil. K tomu – a nejen k tomu – slouží standardní zprávy delegáta. I třída UITabBarController jej – stejně jako většina ostatních složitějších tříd uživatelského rozhraní – podporuje; můžeme jej samozřejmě nastavit nebo načíst prostřednictvím standardního atributu delegate, a "tab bar" mu pak bude posílat následující zprávy (pokud delegát implementuje odpovídající metody):

-(BOOL)tabBarController:(UITabBarController*)tbc
  shouldSelectViewController:(UIViewController*)vc;

Prvá z nich umožňuje dynamicky blokovat aktivaci některé z ikon v situacích, kdy to dočasně z nějakého důvodu nedává smysl. Je ovšem třeba vždy důkladně zvážit, zda je lepší blokovat aktivaci zobrazené ikony, nebo po dobu, kdy odpovídající řídicí objekt aktivovat nelze, ikonu z dolní lišty odstranit.

Jen poměrně málokdy využijeme službu

-(void)tabBarController:(UITabBarController*)tbc
  didSelectViewController:(UIViewController*)vc;

kterou "tab bar" pošle svému delegátu po volbě některé z ikon: typicky většinu operací, jež je v tuto chvíli zapotřebí provést, implementujeme v metodě viewWillAppear: nebo viewDidAppear: odpovídajícího řídicího objektu. Využití této metody delegáta však je čistší, pokud chceme provést nějakou "vnější" operaci – např. ukládat (a po novém spuštění aplikace obnovit) aktivní ikonu, podobně, jako si dnes ukážeme ukládání a obnovení pořadí ikon v liště.

Stejně tak jen málokdy potřebujeme metody

-(void)tabBarController:(UITabBarController*)tbc
  willBeginCustomizingViewControllers:(NSArray*)vcs;-(void)tabBarController:(UITabBarController*)tbc
  willEndCustomizingViewControllers:(NSArray*)vcs;

ačkoli ty již úzce souvisí s naším prvním dnešním úkolem: prvou z těchto zpráv totiž instance třídy UITabBarController pošle svému delegátu předtím, než uživatel začne prostřednictvím konfigurační stránky měnit ikony v dolní liště a jejich pořadí; tu druhou posílá ve chvíli, kdy uživatel tuto práci ukončil (ale konfigurační stránka je dosud zobrazena).

Naproti tomu téměř vždy, když používáme UITabBarController (a máme-li více ikon, než se do lišty vejde), implementujeme v jeho delegátu metodu

-(void)tabBarController:(UITabBarController*)tbc
  didEndCustomizingViewControllers:(NSArray*)vcs
  changed:(BOOL)changed;

Jejím prostřednictvím nám totiž "tab bar" dá na vědomí, že uživatel dokončil změny ikon; navíc ještě v argumentu changed zjistíme, zda skutečně něco změnil, nebo zda se rozhodl ponechat ikony v původním pořadí.

Ukládání stavu lišty

Nyní konečně můžeme implementovat slíbenou funkčnost. Princip je samozřejmě jednoduchý: v metodě delegáta, již jsme si před chvilkou popsali, uložíme stávající pořadí ikon v liště do aplikačních předvoleb; po spuštění aplikace pak ji prostě obnovíme.

Pro zjednodušení budeme předpokládat, že každý z řídicích objektů rámce, jež jsou v našem UITabBarControlleru uloženy, je jiné třídy. Dále pak nebudeme nadále vytvářet řídicí objekty v hlavním NIBu (jak tomu bylo minule), ale vytvoříme je programově po spuštění aplikace.

V praxi tomu tak bývá dost často; pokud bychom řešili situaci kdy je více různých "tabů" representováno touž třídou, musli bychom doplnit nějakou identifikaci obsahu, jež by se ukládala a načítala spolu s třídou samotnou – to už ale ponecháme laskavému čtenáři jako triviální cvičení :)

Ukázkový kód z minulého dílu bychom tedy mohli rozšířit zhruba nějak takto:

#import "A.h" // první vnořený řídicí objekt
#import "B.h" // druhý vnořený řídicí objekt
...
#import "Z.h" // poslední vnořený řídicí objekt

@implementation AppDelegate
@synthesize window;
static UITabBarController *tbc=nil;
-(BOOL)application:(UIApplication*)app
  didFinishLaunchingWithOptions:(NSDictionary*)options {
  tbc=[[UITabBarController alloc] init];
  NSArray *classes=[[NSUserDefaults standardUserDefaults]
    arrayForKey:@"TabOrder"];
  if (!classes) classes=[NSArray arrayWithObjects:
    @"A",@"B", ... ,@"Z",nil];
  NSMutableArray *vcs=[NSMutableArray array];
  for (NSString *cls in classes)
    [vcs addObject:
      [[[NSClassFromString(cls) alloc] init] autorelease]];
  tbc.viewControllers=vcs;
  tbc.delegate=self;
  [self.window addSubview:tbc.view];
  [self.window makeKeyAndVisible];
  return YES;
}
...

Smysl kódu je asi zřejmý: načteme jména tříd, odpovídající našim ikonám, z aplikačních předvoleb; pokud tam nejsou – tedy po prvém spuštění aplikace – použijeme standardní pořadí. Pak postupně vytvoříme odpovídající řídicí objekty, uložíme je do pole vcs a v něm je pak umístíme do řídicího objektu UITabBarController.

Povšimněme si také

• deklarace proměnné tbc jako globální namísto lokální – to proto, abychom se k řídicímu objektu snadno dostali z ostatních metod. Malinko koncepčně čistší by bylo ji umístit mezi instanční proměnné aplikačního delegáta; v naší ukázce jsme si ale ušetřili nutnost zobrazovat rozhraní (deklarace instančních proměnných v implementaci zatím funguje pouze v nejnovějším překladači), a v praxi je to jedno, neboť aplikační delegát existuje v jediné instanci po celou dobu běhu;

• nového řádku tbc.delegate=self – ten zajistí, že náš aplikační delegát bude dostávat od "tab baru" zprávy delegáta a můžeme v něm tedy implementovat i následující metodu:

...
-(void)tabBarController:(UITabBarController*)tbc
  didEndCustomizingViewControllers:(NSArray*)vcs
  changed:(BOOL)changed {
  if (!changed) return;
  [[NSUserDefaults standardUserDefaults]
    setObject:
      [tbc.viewControllers valueForKeyPath:@"class.description"]
    forKey:@"TabOrder"];
}
@end

A to je vše. Nyní aplikace po každé změně obsahu lišty uloží do aplikačních předvoleb seznam tříd řídicích objektů v tom pořadí, v němž uživatel sestavil ikony – a po spuštění je odsud načte a do dolní lišty uloží.

Za zmínku snad stojí jednoduchý trik KVC, který jsme použili pro sestavení pole jmen tříd řídicích objektů:

[tbc.viewControllers valueForKeyPath:@"class.description"]

KVC je velmi šikovný a silný nástroj, který nám dokáže často ušetřit spoustu práce; popsali jsme si jej podrobněji už dávno. Je asi zřejmé, že téhož efektu bychom mohli dosáhnout o poznání delším (a tedy horším, protože náchylnějším k chybám a překlepům) kódem

NSMutableArray *vcnames=[NSMutableArray array];
for (UIViewController *vc in tbc.viewControllers)
  [vcnames addObject:[vc.class description]];

Obsah seriálu (více o seriálu):

Tématické zařazení:

 » Rubriky  » Informace  

 » Rubriky  » Agregator  

 » Rubriky  » Tipy a Triky  

 » Rubriky  » Začínáme s  

 » Rubriky  » Software  

 

 

 

 

Přihlášení k mému účtu

Uživatelské jméno:

Heslo: