Questa domanda è stata posta molto per esempio , ma qui , per quanto posso vedere, non è ancora stata data una risposta completa.
Ho un UITabBarController
con un UINavigationController
come root vc per una delle tabs, che a sua volta ha un MKMapView
come root vc. Il comportamento che voglio è che la mappa si pieghi parzialmente verso l’alto, lasciando la barra delle tabs in posizione (simile all’app Maps).
Finora tutto ciò che sono riuscito a ottenere è che tutto il panorama si arricci, il che non è così bello.
Le soluzioni che ho visto sono impostare la proprietà hidesBottomBarWhenPushed
su NO, il che avrebbe senso, tuttavia, questo non sembra funzionare (a meno che non hidesBottomBarWhenPushed
facendo qualcosa di sbagliato).
Per chiarezza, il mio codice è il seguente:
MyVC *aView = [MyVC init]; aView.modalTransitionStyle = UIModalTransitionStylePartialCurl; aView.hidesBottomBarWhenPushed = NO;
Per la parte che presenta, ho provato le due alternative seguenti, nessuna delle quali sembra funzionare:
[self presentModalViewController:updateStatus animated:YES]; [[self navigationController] presentModalViewController:updateStatus animated:YES];
Qualsiasi aiuto molto apprezzato.
Ho setacciato StackOverflow (e Internet) per una soluzione a questo problema. La domanda è stata posta molte volte, ma come si nota, la risposta non è mai stata sufficiente. Molte soluzioni offrono una soluzione accettabile se non è importante se, ad esempio, una barra degli strumenti inferiore si arriccia.
Altri hanno fornito una soluzione usando UIView
animazioni di UIView
/ CoreAnimation piuttosto che UIModalTransitionStylePartialCurl
come stile di transizione modale; nel peggiore dei casi una soluzione non è consentita nell’App Store e, nel migliore dei casi, non è esattamente lo stesso effetto ottenuto da UIModalTransitionStylePartialCurl
(ad esempio la forma del ricciolo è diversa).
Nessuna di queste soluzioni ha fornito una risposta che imita la soluzione di Apple nell’app Maps (ovvero, utilizzando UIModalTransitionStylePartialCurl
ma lasciando una UIToolbar
non UIToolbar
nella parte inferiore dello schermo).
Continuerò in questa tradizione di risposte incomplete, poiché chiedi informazioni su un UITabBarController
e la mia soluzione non affronta specificamente tale caso. Tuttavia, risolve il problema che avevo, che era quello di ottenere una mezza pagina arricciata con una barra degli strumenti non curvata nella parte inferiore.
Ci deve essere un modo più elegante per farlo, ma è così che sono riuscito.
Il rootViewController
del mio AppDelegate
è una sottoclass di UIViewController
, che chiamerò TAContainerViewController
. TAContainerViewController
gestisce a) il contenuto effettivo dello schermo (il “materiale da arricciare”), TAContentViewController
e b) il contenuto “dietro” il TAContentViewController
(ad esempio le impostazioni), che chiamerò TAUnderCurlViewController
.
La mia istanza di TAContainerViewController
aveva proprietà per un TAContentViewController
e un TAUnderCurlViewController
. L’ UIView
che era il mio contenuto era una sottoview della proprietà della view
di TAContentViewController
; allo stesso modo ciò che l’utente vede sotto l’arricciatura è la proprietà view
di TAUnderCurlViewController
.
Nel metodo init
di TAContainerViewController
mi assicuro di fare quanto segue:
_underCurlVC.modalTransitionStyle = UIModalTransitionStylePartialCurl;
E per arricciare il contenuto da rivelare sotto la pagina, ho impostato un’azione che chiama questo codice:
[self.contentVC presentModalViewController:self.underCurlVC animated:YES];`
dove self
è TAContainerViewController
, contentVC
è un’istanza di TAContentViewController
e underCurlVC
è un’istanza di TAUnderCurlViewController
.
Per chiudere la vista, semplicemente [self.contentVC dismissModalViewControllerAnimated:YES];
.
Qualche stranezza sembra verificarsi con il frame di contentVC
quando la vista modale viene chiusa, quindi ripristino manualmente il frame quando la vista modale viene chiusa.
Ho pubblicato un progetto di esempio con ulteriori dettagli su Github . Speriamo che qualcuno possa prendere questo e trasformarlo in una soluzione leggermente più elegante, oppure espanderlo per funzionare con un UINavigationController
o UITabBarController
. Penso che il trucco sia quello di estrarre i controller di visualizzazione dalle relazioni ben definite nelle sottoclassi di Cocoa, in modo da creare sottoclassi di quelle che i controller di visualizzazione speciali potrebbero eseguire.
La risposta di Tim Arnold ha funzionato alla grande, grazie!
Una trappola a cui fare attenzione: la transizione modale della pagina di arricciatura occuperà l’intero schermo se il controller della vista del contenuto viene aggiunto come figlio del controller della vista del contenitore . Non si può semplicemente aggiungerlo come un bambino, ma nessuno dei metodi del ciclo di vita della vista verrà richiamato sul controller del contenuto (ad es. viewDidLoad
, viewWillAppear
), che potrebbe essere un problema.
Fortunatamente, c’è un modo per aggirare questo. Nel controller del contenitore:
viewDidLoad
viewDidAppear
come un bambino in viewDidAppear
viewWillDisappear
. In questo modo, il controller del contenuto riceve i suoi metodi del ciclo di vita chiamati, pur essendo in grado di eseguire una transizione modale della pagina di arricciatura senza occupare l’intero schermo.
Ecco l’intero codice di una soluzione bare-bones:
@interface XXContainerController : UIViewController @property (strong, nonatomic) UIViewController *contentController; @property (nonatomic) BOOL curled; @end @implementation XXContainerController @synthesize contentController = _contentController; @synthesize curled = _curled; - (void)viewDidLoad { [super viewDidLoad]; self.contentController = [self.storyboard instantiateViewControllerWithIdentifier:@"SomeControllerInStoryboard"]; // Add content controller as child view controller. // This way, it will receive all the view lifecycle events [self addChildViewController:self.contentController]; self.contentController.view.frame = self.view.bounds; [self.view addSubview:self.contentController.view]; [self.contentController didMoveToParentViewController:self]; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; // Remove the content controller as child view controller. // This way, the modal page curl transition will // not take over the whole screen. // NOTE: need to wait until content controller has appeared // (which will happen later). // Achieve this by running the code at the end of the animation loop [UIView animateWithDuration:0 animations:nil completion:^(BOOL finished) { [self.contentController removeFromParentViewController]; }]; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; // Add the content controller as child view controller again // so it receives the view lifecycle events [self addChildViewController:self.contentController]; } - (void)setCurled:(BOOL)curled { if (curled == _curled) return; _curled = curled; // Curl up the content view and show underneath controller's view if (curled) { // Note you can specify any modal transition in storyboard // Eg page curl, flip horizontal [self.contentController performSegueWithIdentifier:@"SomeModalSegueDefinedInStoryboard" sender:self]; // Uncurl and show the content controller's view again } else { [self.contentController dismissModalViewControllerAnimated:YES]; // Have to do this, otherwise the content controller's view // gets messed up for some reason self.contentController.view.frame = self.view.bounds; } } @end