webentwicklung-frage-antwort-db.com.de

Ansichts-Controller: Wie wechselt man programmgesteuert zwischen Ansichten?

Kurz gesagt: Ich möchte zwei Vollbildansichten, in denen ich zwischen Ansicht A und Ansicht B wechseln kann. Ich weiß, dass ich nur einen Tab-Leisten-Controller verwenden kann, aber ich möchte nicht. Ich möchte sehen, wie dies von Hand gemacht wird, um zu erfahren, was unter der Haube vor sich geht.

Ich habe einen UIViewController, der als Root-Controller fungiert:

@interface MyRootController : UIViewController {
    IBOutlet UIView *contentView;
}
@property(nonatomic, retain) UIView *contentView;

@end

Die Inhaltsansicht ist mit einer UIView verbunden, die ich als Unteransicht zur "Ansicht" der Nib hinzugefügt habe. Dies hat grüne Farbe und ich sehe es im Vollbildmodus. Funktioniert gut.

Dann habe ich zwei weitere View-Controller auf die gleiche Weise erstellt. ViewControllerA und ViewControllerB. ViewControllerA hat einen blauen Hintergrund, ViewControllerB hat einen schwarzen Hintergrund. Nur um zu sehen, welche aktiv ist.

In der Implementierung von myRootController mache ich Folgendes:

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

Die -initWithNib-Methode sieht übrigens so aus:

- (id)initWithNib { // Load the view nib
    if (self = [super initWithNibName:@"ViewA" bundle:nil]) {
        // do ivar initialization here, if needed
    }
    return self;
}

Das funktioniert. Ich sehe die Ansicht von ViewControllerA, wenn ich die App starte. Die große Frage ist nun: Ein View Controller verfügt normalerweise über folgende Methoden:

  • (void) viewWillAppear: (BOOL) animiert;
  • (void) viewDidDisappear: (BOOL) animiert;
  • (void) viewDidLoad;

...und so weiter. Wer oder was oder wie würden diese Methoden aufgerufen, wenn ich es "auf meine" Art und Weise ohne einen Tab-Bar-Controller mache? Ich meine: Wenn ich die Klasse dieses ViewControllers allokiere und der View sichtbar wird, muss ich mich dann darum kümmern, diese Methoden aufzurufen? Woher weiß es, dass viewWillAppear, viewDidDisappear oder viewDidLoad? Ich glaube, dass der Tab Bar Controller all diese "Cleverness" unter der Haube hat. Oder liege ich falsch?

UPDATE: Ich habe es getestet. Wenn ich den View Controller freigebe (zum Beispiel: ViewControllerA), erhalte ich keine Protokollmeldung bei viewDidDisappear. Nur beim Zuweisen und Initialisieren des ViewControllerA erhalte ich ein viewDidLoad. Aber das ist es. Alle Zeichen stehen also für die Cleverness von UITabBarController;) und ich muss herausfinden, wie ich das replizieren kann, oder?

52
Thanks

Sie können mit dem einfachsten Befehl removeFromSuperview/insertSubview beginnen und nach und nach Code hinzufügen.


//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

In Kapitel 6 von Beginn der iPhone-Entwicklung finden Sie ein gutes Beispiel für das Wechseln der Ansicht. Den Quellcode dafür finden Sie hier: http://iphonedevbook.com/

SwitchViewController verfügt über den Code zum programmgesteuerten Ändern von Ansichten.


- (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

Wenn ich richtig verstehe, ist das, was Sie erreichen wollen, ziemlich einfach.

Fügen Sie Ihrem Anwendungsdelegierten einfach einen UINavigationController hinzu und führen Sie folgende Schritte aus:

[navigationController pushView:vcA];

Die Delegierten werden entsprechend gerufen:

  • (void) viewWillAppear: (BOOL) animiert;
  • (void) viewDidDisappear: (BOOL) animiert;
  • (void) viewDidLoad;

Und wenn Sie die Ansicht öffnen und eine andere verschieben möchten:

[navigationController popViewControllerAnimated:true];
[navigationController pushView:vcB];

Wenn Sie nicht möchten, dass der navigationController anzeigt, verwenden Sie einfach:

[navigationBar setHidden:YES];

Wobei navigationBar die UINavigationBar ist, die Ihrem UINavigationController entspricht.

21

Dies mag ein altes Problem sein, aber ich bin kürzlich auf dasselbe Problem gestoßen und hatte Schwierigkeiten, etwas zu finden, das funktionierte. Ich wollte zwischen zwei komplementären Ansichtscontrollern wechseln, aber ich wollte, dass der Schalter animiert wird (eingebaute Animationen funktionieren einwandfrei), und ich wollte, dass er wenn möglich mit Storyboards kompatibel ist.

Um die Vorteile des integrierten Übergangs zu nutzen, bietet UIView +transitionFromView:toView:duration:options:completion: Methode funktioniert sehr gut. Es wird jedoch nur zwischen Ansichten gewechselt, nicht zwischen Ansichtscontrollern.

Damit der Übergang zwischen ganzen Ansichts-Controllern und nicht nur Ansichten erfolgt, müssen Sie ein benutzerdefiniertes UIStoryboardSegue erstellen. Unabhängig davon, ob Sie Storyboards verwenden oder nicht, können Sie mit diesem Ansatz den gesamten Übergang kapseln und die Weitergabe relevanter Informationen von einem Ansichts-Controller zum nächsten verwalten. Es geht nur darum, eine Unterklasse von UIStoryboardSegue zu bilden und eine einzelne Methode zu überschreiben, -perform.

Eine Referenzimplementierung finden Sie unter RAFlipReplaceSegue , dem genauen benutzerdefinierten Segment, das ich mithilfe dieses Ansatzes zusammengestellt habe. Als Bonus wird auch der alte Ansichtscontroller durch den neuen ersetzt, wenn er sich in einem UINavigationController -Stack befindet.

2
Ryan Artecona