Programování pro iOS - 40. Další triky UIPopoverControlleru - 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ů



Software

Programování pro iOS - 40. Další triky UIPopoverControlleru

4. května 2011, 00.00 | V předcházejícím dílu jsme se seznámili s třídou UIPopoverController a ukázali jsme si prvý z drobných podrazů, jež na nás její programátoři upletli. Dnes si ukážeme několik dalších.

V minulém pokračování jsme vylepšili naši testovací aplikaci kódem, který po klepnutí do rámce spravovaného třídou SecondViewController zobrazí "popover" se souřadnicemi, na něž uživatel klepl. Ukázali jsme si také drobný podraz, který je ve třídě UIPopoverController se správou paměti i jeho řešení.

Ti, kdo si aplikaci sestavili a vyzkoušeli, zjistili, že nyní "popovery" chodí spolehlivě; jejich velikost však není úplně ideální a také se otevírají poněkud jinde, než by měly – např. po klepnutí doprostřed titulku "aaa" se zobrazí zhruba toto:

Dnes si ukážeme, co s tím dělat.

Velikost "popoveru"

Z nějakých ne úplně zřejmých příčin se programátoři Apple rozhodli "popover" implementovat tak, že ignoruje velikost kořenového rámce řídicího objektu, který je jeho obsahem, a velikost si vždy nastaví podle svého.

Samozřejmě, že ji můžeme sami opravit podle potřeby; v našem případě je nejjednodušším řešením velikost obsahu nastavit přímo, např. takto – stačí do stávající metody tapped: přidat jediný řádek:

-(void)tapped:(UITapGestureRecognizer*)tgr {
  CGPoint pt=[tgr locationInView:self.view];
  xx.text=[NSString stringWithFormat:@"x=%g",pt.x];
  yy.text=[NSString stringWithFormat:@"y=%g",pt.y];
    
  UIViewController *vc=
    [[[UIViewController alloc] init] autorelease];
  vc.view=xx.superview;
  UIPopoverController *pc=[[UIPopoverController alloc]
    initWithContentViewController:vc];
  pc.delegate=(id)self;
  pc.popoverContentSize=vc.view.frame.size;
  [pc presentPopoverFromRect:CGRectMake(pt.x,pt.y,0,0)
    inView:self.view
    permittedArrowDirections:UIPopoverArrowDirectionAny
    animated:YES];
}

To je ale optimální řešení pouze v našem netypickém případě, kdy používáme namísto specifického řídicího objektu přímo objekt třídy UIViewController a vše nastavujeme "zvenku". Za běžných okolností však bývá "vnitřek" popoveru řízen nějakou konkrétní podtřídou, a v takovém případě je lepší nastavit její atribut

@property(nonatomic,readwrite) CGSize contentSizeForViewInPopover;

který standardně vrací "natvrdo" ony na minulém obrázku viditelné rozměry 320 x 1100 bodů.

Pokud bychom tedy měli vlastní třídu (dědice třídy UIViewController), jejíž instanci bychom do "popoveru" ukládali jako jeho contentViewController, a pokud bychom chtěli, aby v tomto případě "popover" ctil velikost rámce, prostě bychom mohli v řídicím objektu implementovat metodu

-(CGSize)contentSizeForViewInPopover {
    return self.view.frame.size;
}

nebo, pokud by to bylo pohodlnější, na tuto hodnotu ve vhodný okamžik nastavit self.contentSizeForViewInPopover.

Umístění "zobáčku"

Toto je poněkud horší a správné řešení se hledá špatně.

Problém spočívá v tom, že firma Apple má v kódu třídy UIPopoverController ošklivou chybu: vyžádáme-li si zobrazení na zadaných souřadnicích uvnitř rámce, popover si souřadnice nepřepočítá na absolutní místo v celé obrazovce. Obecně se proto, použijeme-li zobrazení pomocí metody

-(void)presentPopoverFromRect:(CGRect)rect
  inView:(UIView*)view
  permittedArrowDirections:(UIPopoverArrowDirection)ads
  animated:(BOOL)animated;

v rámci rect, jehož levý horní roh má souřadnice [X,Y] oproti levému hornímu rohu obrazovky, zobrazí "popover" posunutý oproti požadovanému bodu právě o X horizontálně a o Y vertikálně. V naší aplikaci, kde je rámec standardně posunut dolů o výšku stavového řádku (a v případě rámců, jež nemají vlastní ikony, navíc ještě o navigační titulek), se proto "zobáčky" zobrazují příliš vysoko.

Můžeme si ovšem snadno vyžádat přepočtení souřadnic do okna:

-(void)tapped:(UITapGestureRecognizer*)tgr { // nic moc
  ...
  pc.delegate=(id)self;
  pt=[self.view convertPoint:pt toView:self.view.window];
  [pc presentPopoverFromRect:CGRectMake(pt.x,pt.y,0,0)
    inView:self.view
    permittedArrowDirections:UIPopoverArrowDirectionAny
    animated:YES];
}

a bude to fungovat excelentně – bohužel však pouze tak dlouho, dokud je zařízení v základní poloze. Jakmile jím otočíme, zobrazí se popover na zcela "nesmyslných" místech; to proto, že okno samo (na rozdíl od rámců řízených UIViewControllery) nerotuje svůj souřadný systém automaticky podle aktuální polohy iPadu.

Dobrá rada je drahá. Pokud máme k dispozici nadřízený rámec, který je vždy shodný s velikostí okna (ale je řízen UIViewControllerem a tedy jeho souřadná soustava korektně rotuje), můžeme jej využít, a máme hotovo. V případě naší aplikace takový rámec k dispozici máme – je jím kořenový rámec našeho "tab baru". Můžeme tedy problémy s umísťováním "zobáčků" vyřešit spolehlivě a pro všechny situace takto:

-(void)tapped:(UITapGestureRecognizer*)tgr { // lepší
  ...
  pc.delegate=(id)self;
  pt=[self.view convertPoint:pt
    toView:self.tabBarController.view];
  [pc presentPopoverFromRect:CGRectMake(pt.x,pt.y,0,0)
    inView:self.tabBarController.view
    permittedArrowDirections:UIPopoverArrowDirectionAny
    animated:YES];
}

Pokud ovšem v jiné aplikaci takovýto rámec k dispozici není, je to špatné; pak nezbývá, než jej uměle přidělat – nebo, není-li to z nějakého důvodu možné nebo žádoucí, "ručně" přepočítávat polohy podle aktuální pozice zařízení.

Dokonalé

...to zdaleka není. Asi by kupříkladu bylo vhodné, aby se po klepnutí na jiné místo náš "popover" jen přestěhoval a ukázal nové souřadnice; nyní se nám zavře, a to nemusí být úplně ideální. Ale to už si zase ukážeme příště (spolu s programovým zavřením, jež s sebou nese další drobný podraz, zmíněný už v minulé diskusi).

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  

Poslat článek

Nyní máte možnost poslat odkaz článku svým přátelům:

Váš e-mail:

(Není povinný)

E-mail adresáta:

Odkaz článku:

Vzkaz:

Kontrola:

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

Kód pro ověření

 

 

 

 

 

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

Uživatelské jméno:

Heslo: