Programování pro iOS - 42. UISplitViewController - 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:

Seriály

Více seriálů



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):

Tématické zařazení:

 » Rubriky  » Informace  

 » Rubriky  » Agregator  

 » Rubriky  » Tipy a Triky  

 » Rubriky  » Začínáme s  

 » Rubriky  » Software  

Diskuse k článku

 

Vložit nový příspěvek   Sbalit příspěvky

 

Xcode

Autor: hroch32 Muž

Založeno: 18.05.2011, 17:13
Odpovědí: 0

Na info o Xcode 4 se rozhodně těším ;-)

Odpovědět na příspěvek

RE: Xcode

Autor: Peter Macik Muž

Založeno: 18.05.2011, 18:18

Ja tiez... Mne osobne sa ten Xcode 4 nejako nepozdava - vsetko v jednom okne, je to tam natlacene, stale je potrebne na nieco klikat a posuvat aby sme mali zobrazene to co chceme... Budem robit v 3.2.6 dokedy sa bude dat, a pre Lion to len skompilujem vo verzii 4.

Odpovědět na příspěvek

RE: RE: Xcode

Autor: hroch32 Muž

Založeno: 18.05.2011, 21:43

Sice používám i dneska "All in one" nastavení, ale v Xcode 3 je i při tomto "módu" mnoho věcí v samostatném okně (project/target settings, kupříkladu). Ono to asi chce mít veliký monitor.

V tuhle chvíli mi nejvíce vadí chybějící podpora pro IB pluginy, několik zásadních nedodělků a bugů a nevyjasněnost podpory starých formátů projektů, respektive otevírání nových projektů ve starších Xcode (v tom snad ale má nejnovější verse již jasno a podporuje vše od formátu Xcode 3.1).

Odpovědět na příspěvek

RE: RE: RE: Xcode

Autor: PH Muž

Založeno: 18.05.2011, 22:02

Zatím zůstávám u trojky. Asi jde hlavně o zvyk...

Odpovědět na příspěvek

4

Autor: OC Muž

Založeno: 18.05.2011, 22:36
Odpovědí: 0

Pár věcí je ve čtyřce opravdu pěkných. Ale pár je totálně na zabití. Integrovaný IB s nemožností postavit si inspektor a paletu vedle sebe je jedna z nejvýraznějších... a je toho víc, bude to v článcích :)

Mimochodem, řeším (a zatím jsem nevyřešil) problém s workspaces -- nevidíte do toho někdo lépe? Zkoušel jsem workspace, kde byl vedle sebe projekt s knihovnou (bylo to pro iOS, takže statickou) a aplikace, která ji linkuje -- nejklasičtější možná struktura. Ale

(a) nepodařilo se mi zjistit, jak docílit toho, aby aplikace viděla headery knihovny: nastavení \"public\" nepomohlo, variant #import jsem vyzkoušel nepočítaných, všechny marně :( Nakonec jediné, co pomohlo, bylo přidat explicitně do header search path aplikace rekursivní $(BUILT_PRODUCTS_DIR), což se mi jeví jako kapku dost prasárna;

(b) ačkoli workspace skutečně automaticky zdetekovalo závislost natolik, že při buildu po cleanu korektně zbuildovalo nejprve knihovnu a pak aplikaci, nepodařilo se mi _vůbec_ najít _žádný_ způsob, jak je přimět, aby po změně zdrojáku v knihovně automaticky přebuildovalo obojí :( Zkoušel jsem přidat projekt knihovny do aplikace (což by ve workspaces snad nemělo být zapotřebí), zkoušel jsem nastavit explicitní závislost targetů, vše in vain.

Neznáte někdo řešení?

Odpovědět na příspěvek

 

 

Odpověď na příspěvek:

Zatím zůstávám u trojky. Asi jde hlavně o zvyk...


Jméno:

Pohlaví:

,

E-mail:

Předmět:

Příspěvek:

 

Kontrola:

Do spodního pole opište z obrázku 5 znaků:

Kód pro ověření

 

 

 

 

Nejčtenější články
Nejlépe hodnocené články
Apple kurzy

 

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

Uživatelské jméno:

Heslo: