web-dev-qa-db-fra.com

Contrôleurs de vue: comment basculer entre les vues par programme?

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:

  • (void) viewWillAppear: (BOOL) animé;
  • (void) viewDidDisappear: (BOOL) animé;
  • (void) viewDidLoad;

...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?

52
Thanks

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];

39
Chilly Zhong

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];

}
50
nevan king

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:

  • (vide) viewWillAppear: (BOOL) animé;
  • (void) viewDidDisappear: (BOOL) animé;
  • (void) viewDidLoad;

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.

21
Pablo Santa Cruz

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.

2
Ryan Artecona