En bref: je veux avoir deux vues plein écran, où je peux basculer entre la vue A et la vue B. Je sais que je pourrais simplement utiliser un contrôleur de barre d'onglets, mais je ne veux pas. Je veux voir comment cela se fait à la main, pour apprendre ce qui se passe sous le capot.
J'ai un UIViewController qui agit comme un contrôleur racine:
@interface MyRootController : UIViewController {
IBOutlet UIView *contentView;
}
@property(nonatomic, retain) UIView *contentView;
@end
Le contentView est connecté à une UIView que j'ai ajoutée comme sous-vue à la "vue" de la Nib. Cela a une couleur verte et je le vois en plein écran. Fonctionne bien.
Ensuite, j'ai créé deux autres contrôleurs de vue à peu près de la même manière. ViewControllerA et ViewControllerB. ViewControllerA a un fond bleu, ViewControllerB a un fond noir. Juste pour voir lequel est actif.
Donc, dans la mise en œuvre de myRootController, je fais ceci:
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
ViewControllerA *vcA = [[ViewControllerA alloc] initWithNib];
[self.contentView addSubview:vcA.view];
[cvA release];
}
Soit dit en passant, la méthode -initWithNib ressemble à ceci:
- (id)initWithNib { // Load the view nib
if (self = [super initWithNibName:@"ViewA" bundle:nil]) {
// do ivar initialization here, if needed
}
return self;
}
Ça marche. Je vois la vue de ViewControllerA lorsque je démarre l'application. Mais maintenant, la grande question est: Un contrôleur de vue a généralement toutes ces méthodes comme:
...etc. Qui ou quoi, ou comment ces méthodes seraient-elles appelées si je le fais "à ma façon" sans contrôleur de barre d'onglets? Je veux dire: si j'alloue cette classe ViewController et que la vue est visible, devrais-je prendre soin d'appeler ces méthodes? Comment sait-il que viewWillAppear, viewDidDisappear ou viewDidLoad? Je crois que le Tab Bar Controller a toute cette "intelligence" sous le capot. Ou ai-je tort?
MISE À JOUR: je l'ai testé. Si je libère le contrôleur de vue (par exemple: ViewControllerA), je ne recevrai aucun message de journal sur viewDidDisappear. Ce n'est que lors de l'allocation et de l'initialisation du ViewControllerA que j'obtiens un viewDidLoad. Mais c'est tout. Donc, tous les signes représentent l'intelligence de UITabBarController maintenant;) et je dois comprendre comment reproduire cela, non?
Vous pouvez commencer à partir de la méthode removeFromSuperview/insertSubview la plus simple et y ajouter du code petit à petit.
//SwitchViewController.h
#import
@class BlueViewController;
@class YellowViewController;
@interface SwitchViewController : UIViewController {
IBOutlet BlueViewController *blueViewController;
IBOutlet YellowViewController *yellowViewController;
}
- (IBAction)switchViews:(id)sender;
@property (nonatomic, retain) BlueViewController *blueViewController;
@property (nonatomic, retain) YellowViewController *yellowViewController;
@end
//1. remove yellow view and insert blue view
- (IBAction)switchViews:(id)sender {
if(self.blueViewController.view.superview == nil)
{
[yellowViewController.view removeFromSuperview];
[self.view insertSubview:blueViewController.view atIndex:0];
}
}
//2. appear=insert, disappear=remove
if(blueViewController.view.superview == nil)
{
[blueViewController viewWillAppear:YES];
[yellowViewController viewWillDisappear:YES];
[yellowViewController.view removeFromSuperview];
[self.view insertSubview:self.blueViewController.view atIndex:0];
[yellowViewController viewDidDisappear:YES];
[blueViewController viewDidAppear:YES];
}
//3. now add animation
[UIView beginAnimations:@"View Flip" context:nil];
[UIView setAnimationDuration:1.25];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
//blue view will appear by flipping from right
if(blueViewController.view.superview == nil)
{
[UIView setAnimationTransition: UIViewAnimationTransitionFlipFromRight
forView:self.view cache:YES];
[blueViewController viewWillAppear:YES];
[yellowViewController viewWillDisappear:YES];
[yellowViewController.view removeFromSuperview];
[self.view insertSubview:self.blueViewController.view atIndex:0];
[yellowViewController viewDidDisappear:YES];
[blueViewController viewDidAppear:YES];
}
[UIView commitAnimations];
Il y a un bel exemple de changement de vue dans le chapitre 6 du début du développement iPhone. Vous pouvez voir le code source pour cela ici: http://iphonedevbook.com/
SwitchViewController a le code pour changer les vues par programme.
- (IBAction)switchViews:(id)sender
{
if (self.yellowViewController == nil)
{
YellowViewController *yellowController = [[YellowViewController alloc]
initWithNibName:@"YellowView" bundle:nil];
self.yellowViewController = yellowController;
[yellowController release];
}
[UIView beginAnimations:@"View Flip" context:nil];
[UIView setAnimationDuration:1.25];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
UIViewController *coming = nil;
UIViewController *going = nil;
UIViewAnimationTransition transition;
if (self.blueViewController.view.superview == nil)
{
coming = blueViewController;
going = yellowViewController;
transition = UIViewAnimationTransitionFlipFromLeft;
}
else
{
coming = yellowViewController;
going = blueViewController;
transition = UIViewAnimationTransitionFlipFromRight;
}
[UIView setAnimationTransition: transition forView:self.view cache:YES];
[coming viewWillAppear:YES];
[going viewWillDisappear:YES];
[going.view removeFromSuperview];
[self.view insertSubview: coming.view atIndex:0];
[going viewDidDisappear:YES];
[coming viewDidAppear:YES];
[UIView commitAnimations];
}
Si je comprends bien, ce que vous essayez d'accomplir est assez simple.
Ajoutez simplement un UINavigationController sur votre délégué d'application et faites:
[navigationController pushView:vcA];
Les délégués seront appelés en conséquence:
Et lorsque vous voulez faire apparaître la vue et en pousser une autre:
[navigationController popViewControllerAnimated:true];
[navigationController pushView:vcB];
Si vous ne voulez pas que le navigateur de navigation s'affiche, utilisez simplement:
[navigationBar setHidden:YES];
Où navigationBar est le UINavigationBar correspondant à votre UINavigationController.
C'est peut-être un vieux problème, mais j'ai récemment rencontré le même problème et j'ai eu du mal à trouver quelque chose qui fonctionnait. Je voulais basculer entre deux contrôleurs de vue complémentaires, mais je voulais que le commutateur soit animé (les animations intégrées fonctionnent bien), et je voulais qu'il soit compatible avec les storyboards si possible.
Pour tirer parti de la transition intégrée, UIView's +transitionFromView:toView:duration:options:completion:
fonctionne parfaitement. Mais, il fait uniquement la transition entre les vues, pas les contrôleurs de vue.
Pour que la transition se fasse entre des contrôleurs de vue entiers, et pas seulement des vues, la création d'un UIStoryboardSegue
personnalisé est la voie à suivre. Que vous utilisiez ou non des storyboards, cette approche vous permet d'encapsuler toute la transition et de gérer le passage des informations pertinentes d'un contrôleur de vue au suivant. Cela implique uniquement de sous-classer UIStoryboardSegue
et de remplacer une seule méthode, -perform
.
Pour une implémentation de référence, voir RAFlipReplaceSegue
, la séquence personnalisée exacte que j'ai créée en utilisant cette approche. En prime, il remplace également l'ancien contrôleur de vue par le nouveau s'il se trouve dans une pile UINavigationController
.