Programování pro iOS - 28. Základní služby - 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

 

Odkud pochází fotografka Anne Erhard?

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

Seriály

Více seriálů



Informace

Programování pro iOS - 28. Základní služby

9. února 2011, 00.00 | Už umíme vytvářet řídicí objekty rámců a jimi spravované rámce. Dnes se podíváme na základní služby, jež nám tyto objekty nabízejí. Začneme vzájmeným překrýváním obrazovek.

První a základní "obrazovku" – tedy samozřejmě stejně velký rámec, obsahující nějaké prvky grafického uživatelského rozhraní, a spravovaný nějakou podtřídou UIViewControlleru – standardně aktivuje delegát aplikace v metodě application:didFinishLaunchingWithOptions:; odpovídající kód je obvykle vygenerován z projektového vzoru Xcode a vypadá zhruba nějak takto:

-(BOOL)application:(UIApplication*)application
  didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {   
    [window addSubview:viewController.view];
    [window makeKeyAndVisible];
   return YES;
}

Jak ale tuto obrazovku nahradíme jinou, spravovanou odlišným řídicím objektem?

Ačkoli v principu by bylo možné přidávat (nebo zaměňovat) vnořené rámce v okně přímo dalšími příkazy addSubview:, bylo by to velmi komplikované a navíc bychom se museli o všechny odpovídající efekty postarat ručně. Řídicí objekty rámců však nabízejí služby, jež požadovanou funkci zajistí snadno a velmi pohodlně.

Za běžných okolností se v iOSu setkáváme s třemi základními mechanismy vzájemného přepínání "obrazovek":

• "navigační struktura", v níž se zprava objevují nové "obrazovky" a doleva se vracíme ke starším; standardně je doprovázena lištou u horního okraje obrazovky s tlačítkem "zpět" specifického tvaru;

• "tab-bar", kde máme k dispozici několik "obrazovek", mezi nimiž přepínáme pomocí ikon při dolním okraji;

• nejobecnější struktura modálního překrývání, kde můžeme kdykoli aktuální obrazovku překrýt jakoukoli jinou a opět se vrátit k té původní.

Zpráva presentModalViewController:animated:

Prvé dvě složitější služby jsou realizovány pomocí speciálních řídicích objektů a ukážeme si je později. Třetí je nejjednodušší a je k dispozici v libovolném dědici třídy UIViewController; stačí poslat mu zprávu

-(void)presentModalViewController:(UIViewController*)mvc
       animated:(BOOL)animated;

kde argument mvc je libovolný jiný UIViewController. Knihovní kód se pak automaticky postará o to, aby se rámce, jež patří řídicímu objektu mvc, umístily na obrazovku, kde překryjí stávající rámce příjemce zprávy.

Zároveň je možné si pomocí přepínače animated vyžádat, aby se nové rámce na obrazovce objevily pomocí některé ze standardních animací podporovaných systémem iOS. Standardní animací pro tento případ je "vyjetí zdola"; alternativně máme k dispozici animace

UIModalTransitionStyleFlipHorizontal – "přetočení" rámce, běžně používané po stisknutí tlačítka (i) v pravém dolním rohu;

UIModalTransitionStyleCrossDissolve – animace ve stylu "filmové prolínačky";

UIModalTransitionStylePartialCurl – starý rámec se "odloupne", a ponechá na obrazovce obsah nového, částečně překrytý v horní části starým – jde o týž efekt, který používá např. standardní aplikace Maps, klepneme-li v ní na ikonku v pravém dolním rohu;

• pro úplnost, standardní animace "zdola nahoru" se jmenuje UIModalTransitionStyleCoverVertical.

Pro určení požadované animace použijeme atribut modalTransitionStyle nového řídicího objektu. Pokud bychom tedy chtěli např. zobrazit rámce spravované řídicím objektem foo pomocí "přetočené" animace, použijeme ve výchozím řídicím objektu (který tedy obsahuje mj. také instanční proměnnou foo) zhruba takovouto implementaci:

-(IBAction)flipToTheOtherView:sender {
  foo.modalTransitionStyle=UIModalTransitionStyleFlipHorizontal;
  [self presentModalViewController:foo animated:YES];
}

Samozřejmě, že – v závislosti na konkrétní struktuře naší aplikace – nemusíme "překryvný" řídicí objekt a jeho rámce udržovat v paměti pořád; naopak, mnohdy je vhodnější je vytvořit cíleně právě až ve chvíli, kdy jsou zapotřebí, nějak takto:

-(IBAction)flipToTheOtherView:sender {
  FlippedViewController *foo=[[FlippedViewController alloc] init];
  foo.modalTransitionStyle=UIModalTransitionStyleFlipHorizontal;
  [self presentModalViewController:foo animated:YES];
  [foo release];
}

Pro iPad s jeho velkou obrazovkou máme navíc možnost využít několik specifických výjimek z dříve zmíněného obecného pravidla, že hlavní rámec musí překrývat celou obrazovku a být neprůhledný. Na rozdíl od iPhone můžeme v aplikacích pro iPad vedle atributu modalTransitionStyle nastavit také podobný atribut modalPresentationStyle; možné hodnoty jsou tyto:

UIModalPresentationFullScreen: standardní překrytí celé obrazovky, tak, jak je to běžné na iPhone;

UIModalPresentationPageSheet: je-li zařízení orientováno na výšku ("portrait"), funguje stejně jako minulý případ. Pokud je ale iPad orientován na šířku ("landscape"), nový rámec je stále pouze tak široký, jaká je v této orientaci výška obrazovky; po stranách tedy zůstanou volné okraje skrz něž je viditelný starý rámec (překrytý šedým poloprůhledným závojem);

UIModalPresentationFormSheet: jak výška, tak i šířka nového rámce jsou menší, než velikost obrazovky iPadu. Starý rámec – opět překrytý šedým poloprůhledným závojem – je vidět všude kolem. Nový rámec je vycentrován na obrazovce. Běžně se tato varianta používá v případech, kdy je třeba v novém rámci vkládat text; po otevření obrazovky se totiž nový rámec posune automaticky nahoru, takže je stále viditelný celý;

UIModalPresentationCurrentContext: atribut se dědí od nadřízeného řídicího objektu.

Zpráva dismissModalViewControllerAnimated:

Chceme-li opět rámce modálního řídicího objektu z obrazovky odstranit a vrátit se k původnímu vzhledu a řídicímu objektu, použijeme zprávu dismissModalViewControllerAnimated:. Můžeme ji stejně dobře poslat kterémukoli z obou objektů – jak starému, tak i novému; ačkoli o návrat do původního stavu se vždy fakticky stará ten starý, nový mu tuto zprávu automaticky předá. (Stojí asi za zmínku, že projektové vzory v Xcode této služby nevyužívají a namísto toho obsahují zbytečně komplikované explicitní předávání zprávy "starému" řídicímu objektu. Není však žádný důvod to dodržovat a tak zbytečně komplikovat vlastní kód.)

Nejjednodušší kód v novém řídicím objektu pro odstranění jeho rámců by mohl vypadat nějak takto (v našem posledním příkladu by tedy tato metoda byla součástí třídy FlippedViewController):

-(IBAction)flipBackToTheOriginalView:sender {
  [self dismissModalViewControllerAnimated:YES];
}

Vyžádáme-li si argumentem YES animaci, použije se odpovídající inverzní animace k té, jíž se rámce na obrazovku dostaly, a jež je stále uložena v atributu modalTransitionStyle.

Více řídicích objektů nad sebou

Výše popsaným způsobem přes sebe můžeme "navrstvit" libovolně mnoho řídicích objektů: kořenový řídicí objekt, jehož rámec je uložen do okna kódem z prvého příkladu na začátku článku, tak může presentovat rámce řídicího objektu A; ten sám přes sebe překryje rámce řídicího objektu B, který zase presentuje řídicí objekt C, a tak dále.

Aby si knihovní kód "udržel přehled", obsahují řídicí objekty dva šikovné atributy, jež můžeme využít samozřejmě také programově, kdykoli se nám to hodí:

@property(nonatomic,readonly)UIViewController*modalViewController
@property(nonatomic,readonly)UIViewController*parentViewController

Pokud je řídicí objekt sám překryt rámci nějakého jiného řídicího objektu – tj. poté, kdy sám dostal zprávu presentModalViewController:animated: –, je tento překrývající řídicí objekt uložen v atributu modalViewController.

Jestliže řídicí objekt sám nějaký jiný řídicí objekt překrývá – tj. poté, kdy sám byl argumentem zprávy presentModalViewController:animated: zaslané jinému řídicímu objektu –, je tento překrytý řídicí objekt uložen v atributu parentViewController.

Pokud se takto vzájemně překrývá celý řetěz řídicích objektů a my některému z nich pošleme zprávu dismissModalViewControllerAnimated:, platí následující logika:

• pokud příjemce zprávy nemá žádný modalViewController (obsahuje-li tento atribut hodnotu nil), nedělá nic jiného, než že ji předá objektu parentViewController (tuto službu jsme si vysvětlili v minulém odstavci);

• má-li naopak příjemce modalViewController, budou právě rámce tohoto řídicího objektu (tedy právě toho, který příjemce překrývá) a všech případných dalších, odstraněny.

Ve druhém případě navíc platí, že vyžádáme-li si animaci argumentem YES, proběhne pouze u rámců nejvyššího viditelného řídicího objektu; všechny případné další budou odstraněny najednou a bez animací.

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: