2010-04-21 21 views
9

Ich habe zwei Ansichten, die modal nacheinander angezeigt werden müssen. Dies funktioniert nicht, wenn wir nacheinander ablehnen und anzeigen, wie folgt:Korrekte Art aufeinanderfolgende modalViews anzuzeigen

[rootController dismissModalViewControllerAnimated: YES]; 
[rootController presentModalViewController: psvc animated: YES]; 

Die zweite Modalansicht wird einfach nicht angezeigt.

Ich habe ein Update gesehen, dass so etwas wie das war:

[rootController dismissModalViewControllerAnimated: YES]; 
[[UIApplication sharedApplication] beginIgnoringInteractionEvents]; 
[self performSelector: @selector(seekModal) withObject: nil afterDelay: 0.5]; 
[[UIApplication sharedApplication] endIgnoringInteractionEvents]; 

Das Problem ist, dass dies nicht die ganze Zeit arbeiten (die Verzögerung erforderlich ist überlegen, manchmal).

Eine andere mögliche Lösung wäre die Animation zu beseitigen:

[rootController dismissModalViewControllerAnimated: NO]; 
[rootController presentModalViewController: psvc animated: YES]; 

Aber ich würde wirklich die Animation halten möchte, um das Gefühl zu halten, dass die erste Modal aus dem Weg ist. Irgendwelche Vorschläge?

+3

Warum gerade nicht auf Modal-View-Controller, der seine Ansicht ändert? Zwei Modal View Controller in einer Reihe wären ein bisschen nervig. – bpapa

+0

Wenn sie "konsekutiv" sind, sollten Sie die Navigation verwenden. –

+0

Sind Sie 100% sicher, dass die Abwahl der 1. Modalansicht und die Eröffnung der 2. Modalität beide im Kontext des Hauptthreads durchgeführt werden? – yonel

Antwort

17

EDIT: der „richtige“ -Mechanismus dies in iOS5 + zu tun, wäre es, die – dismissViewControllerAnimated:completion: Methode zu verwenden, und legt die sequenziellen View-Controller aus dem Abschluss-Block.


Der Viewcontroller, die modal seine viewDidDisappear haben gezeigt wird: animierte: Methode, wenn die Animation modal-Entlassung genannte abgeschlossen ist.AFIK Dies ist der einzige Ort, an dem Sie einen nachfolgenden presentModalViewController starten können: animated: call.

Ich habe eine Klasse, die ich für die Darstellung von Modal View-Controllern verwende und implementiert die Logik, nach der Sie suchen, über einen Callback zum präsentierenden View-Controller, sobald die Kündigung abgeschlossen ist. Um diese Klasse zu verwenden, weisen Sie einfach/init eine Instanz zu und präsentieren Sie sie mit dem normalen presentViewController: animated: call. Implementieren Sie die folgende Methode auf dem präsentierenden View-Controller:

- (void) modalViewControllerDidDismiss:(UIViewController *)modalViewController 

Dies wird sofort die modalen View-Controller aufgerufen werden sind weg, und Sie können einen neuen modalen View-Controller zu diesem Zeitpunkt darzustellen.

Eine nette Sache auch - da diese Klasse eine Spezialisierung von UINavigationController ist, können Sie die navigationBar nach Belieben ein- und ausschalten. Die Klasse verfügt auch über eine integrierte Logik, um eine Schaltfläche zum Schließen anzuzeigen, wie Sie möchten.

Hier ist die Klassendefinition:

@protocol TSModalViewControllerDelegate 

- (void) modalViewControllerDidDismiss: (UIViewController*) modalViewController; 

@end 

@interface TSModalViewController : UINavigationController 
{ 
    UIViewController* _originalParentViewController; 
} 
@property BOOL dismissButtonHidden; 

- (id) initWithViewController: (UIViewController*) vc; 
- (id) initWithClass: (Class) c; 
- (id) initWithClass: (Class) c nibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil; 

@end 

Und die Klassenimplementierung:

@implementation TSModalViewController 
@synthesize dismissButtonHidden; 

- (id) initWithViewController: (UIViewController *)vc 
{ 
    return [super initWithRootViewController: vc]; 
} 

- (id) initWithClass:(Class)c 
{ 
    UIViewController* vc = [[[c alloc] init] autorelease]; 
    return [self initWithViewController: vc]; 
} 

- (id) initWithClass: (Class) c nibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 
{ 
    UIViewController* vc = [[[c alloc] initWithNibName:nibNameOrNil bundle:nibBundleOrNil] autorelease]; 
    return [self initWithViewController: vc]; 
} 

- (void) viewDidAppear: (BOOL) animated 
{ 
    [super viewDidAppear: animated]; 

    [_originalParentViewController release]; 
    _originalParentViewController = [self.parentViewController retain]; 

    if (!self.dismissButtonHidden) 
    { 
     UIBarButtonItem* dismissButton = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem: UIBarButtonSystemItemStop 
                         target: self 
                         action: @selector(onDismiss:)] autorelease]; 

     UIViewController* rootViewController = [self.viewControllers objectAtIndex:0]; 

     rootViewController.navigationItem.leftBarButtonItem = dismissButton; 
     self.navigationBarHidden = NO; 
    } 
} 

- (void) viewDidDisappear:(BOOL)animated 
{ 
    [super viewDidDisappear: animated]; 
    if ([_originalParentViewController respondsToSelector: @selector(modalViewControllerDidDismiss:)]) 
    { 
     [_originalParentViewController performSelector: @selector(modalViewControllerDidDismiss:) withObject: self]; 
    } 
} 

- (void) dismissModalViewControllerAnimated:(BOOL)animated 
{ 
    return [self.parentViewController dismissModalViewControllerAnimated: animated]; 
} 

- (void) onDismiss: (id) sender 
{ 
    [self.parentViewController dismissModalViewControllerAnimated: YES]; 
} 

- (void) didReceiveMemoryWarning 
{ 
    [super didReceiveMemoryWarning]; 
} 

- (void) viewDidUnload 
{ 
    [super viewDidUnload]; 
} 

- (void)dealloc 
{ 
    [_originalParentViewController release]; 
    [super dealloc]; 
} 

@end 

und hier ist, wie Sie es (im Rahmen von einigem normalen View-Controller) verwenden können:

- (void) onShowIt:(id)sender 
{ 
    TSModalViewController* mvc = [[[TSModalViewController alloc] initWithClass: [MyModalViewController class] nibName: @"MyModalViewController" bundle:nil] autorelease]; 
    mvc.dismissButtonHidden = YES; // set to no if you don't want an "automatic" close button 

    [self presentModalViewController: mvc animated: YES]; 
} 

und, hier ist die Rückruf-Callback-Methode, die einen neuen modalen View-Controller präsentiert:

- (void) modalViewControllerDidDismiss:(UIViewController *)modalViewController 
{ 
    MyModalViewController* vc = [[[MyModalViewController alloc] initWithNibName: @"MyModalViewController" bundle:nil] autorelease]; 
    vc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal; 

    TSModalViewController* mvc = [[[TSModalViewController alloc] initWithViewController: vc] autorelease]; 

    [self presentModalViewController: mvc animated: YES]; 
} 
0

rootController kann feststellen, wann der letzte der Modal-View-Controller darüber verschwunden ist, weil er einen viewDidAppear: erhalten wird. Haben Sie versucht, den presentModalViewController des folgenden View-Controllers mit dem zu verknüpfen?

+0

Sie stoßen immer noch auf Timing-Probleme ... viewDidAppear wird aufgerufen, bevor die Ansicht scheinbar tatsächlich erschienen ist. –

+0

Es gibt immer 'performSelector: foo afterDelay: 0' was in viewDidAppear funktionieren könnte ... –

0

Wenn Sie mehrere Ansichtsanimationen wirklich miteinander verknüpfen möchten, würde ich vorschlagen, die Animationslogik selbst zu bearbeiten. Es ist nicht zu schwierig, und dann können Sie fein abgestimmte Kontrolle über die Darstellung der Ansichten haben. Ich schrieb hier etwas ähnliches für eine weitere Frage auf:

iOS -- how do you control the size of a modal view controller?

Sie können nur auf die Ansicht animieren, animieren die Ansicht aus, und wenn Ihr animationDidStop Selektor genannt wird, animiert Ihre zweiten Blick auf. Der nette Teil davon ist, dass Sie auch mit Opazität und Animationsrichtung der Ansicht spielen können und genau entscheiden können, wann die Ansichten angezeigt werden sollen. Zum Beispiel könnte die zweite Ansicht über die erste Ansicht rutschen, wenn die erste Ansicht wegrutscht. Sie müssen nicht darauf warten, bis der erste die Animation abgeschlossen hat.

+0

Interessante Idee. Es scheint, als ob dich das aus MVC heraus zwingt, oder? Als ob Sie mit zwei Ansichten und einem Controller enden würden. –

+0

MVC bedeutet nicht unbedingt eins von beiden; Es geht darum, diese Komponenten voneinander zu trennen und jedem seinen Teil zu überlassen. Es ist tatsächlich ziemlich üblich, dass ein View-Controller mehrere Ansichten verwaltet. Schließlich sind viele/die meisten UI-Komponenten, die Sie der Ansicht eines View-Controllers hinzufügen (Schaltflächen, Bilder usw.) und animieren, nur Ansichten selbst. Es ist besser, sich jeden View-Controller als einen Vollbild-Teil Ihres Programms und den Kopf hinter diesem Abschnitt der App vorzustellen. Der Controller ist die Logik, die die Modelle und Ansichten miteinander verbindet. – atticus

0

Bezieht sich Ihr Problem auf "eine modale Ansicht in einer modalen Ansicht anzeigen"? ich Post eine Antwort darüber haben sich hier: iPhone modal view inside another modal view?

+0

Nicht wirklich. Es geht darum, eine modale Ansicht zu schließen und eine andere zu öffnen. iOS scheint sich zu verschlucken, wenn Sie eine Ansicht zu nah schließen und präsentieren. Dies ist insbesondere ein Problem mit dem Kameraaufnehmer, da es eine hohe Lade-/Entladezeit hat. Wenn Sie den Kamera-Picker verwerfen und etwas anderes zeigen möchten, können Sie sich allen möglichen seltsamen Verhaltensweisen gegenübersehen. –

0

Die beste Lösung, die ich für so etwas gefunden (wenn sie alle gleich Kinder von der übergeordneten Ansicht sind) ist, ihre Ansichten auf eine UIScrollView mit Paging-Patch freigegeben, (Sie können ein Seitensteuerelement am unteren Rand hinzufügen, um es zu verdeutlichen und zur Navigation zu verwenden). Fügen Sie dann die Ansichten der Controller der Seitenansicht hinzu, wenn sie auf dem Bildschirm angezeigt werden, und entfernen Sie sie, wenn sie nicht angezeigt werden.

Möglicherweise müssen Sie auch den Dummy-Aufruf -viewWillAppear und -viewWillDisappear aufrufen, wenn die Controller darauf angewiesen sind, dass sie aufgerufen werden. Es fühlt sich ein bisschen hack-isch an, wenn du alles programmierst, aber sobald du es funktioniert hast, sieht es glatt und natürlich aus, und es gibt kein Warten darauf, eine Ansicht zu animieren und dann die nächste auf einmal zu animieren ist weg.

0

Ich finde die modale Ansicht des -viewDidDissapear mit sehr gut Methoden auf das präsentierende View-Controller-Arbeit aufzurufen. Ein Vorteil ist die Möglichkeit, die Freigabe auf dem Modal-View-Controller zu verzögern. Bitte posten Sie alle Verbesserungen, die ich machen kann. Meine Inspiration für die Erstellung dieses Protokolls kam von iOS 5 "UseViewControllerAnimated: Ergänzung:" Ergänzung zu UIViewController. Ich wollte diese Funktionalität in iOS 4.3.


PresentorDelegateProtocol.h

@protocol PresentorDelegateProtocol <NSObject> 
@optional 

/* 

Extra protocol methods defined in protocol for flexibility. 
Main methods are: 
- (void)dismissPresentingModalViewController:(id)modalView animated:(BOOL)animated; 
- (void)modalViewDissapeared:(id)modalView; //used in modal view's -viewDidDissapear 

*/ 

- (void)dismissPresentingModalViewController:(id)modalView animated:(BOOL)animated; 
- (void)modalViewDissapeared:(id)modalView; 

// use the block in this method send messages to save state, etc. This is the one I like to use. 
- (void)dismissPresentingModalViewController:(id)modalView animated:(BOOL)animated withBlock:(void(^)())block; 

// use in other classes that are not controlling dismissal of the modal view 
- (void)executeBlockOnModalDissapearance: (void(^)())block; 

@end 

PresentingViewController.h

#import "PresentorDelegateProtocol.h" 
@interface PresentingViewController : UIViewController <PresentorDelegateProtocol> 
- (void)showModalVC; 
@end 

ModalViewController.h

#import "PresentorDelegateProtocol.h" 
@interface ModalViewController : UIViewController 
@property (nonatomic, assign) id <PresentorDelegateProtocol> presentorDelegate; 
- (void)close; 
@end 

PresentingViewController.m

#import "PresentingViewController.h" 
#import "ModalViewController.h" 
@implementation PresentingModalViewController 
- (void)showModalVC 
{ 
    ModalViewController *modalVC = [[ModalViewController alloc] initWithNibName:@"ModalViewController" bundle:nil]; 
    modalVC.presentorDelegate = self; 
    [self presentModalViewController:modalVC animated:YES]; 
} 
- (void)dismissPresentingModalViewController:(id)modalView animated:(BOOL)animated 
{ 
    if ([modalView isKindOfClass:[ModalViewController class]]) { 
     NSLog(@"Can invoke based on class"); 
    } 
    [self dismissModalViewControllerAnimated:animated];  
} 
- (void)dismissPresentingModalViewController:(id)modalView animated:(BOOL)animated withBlock:(void(^)())block 
{ 
    block(); 
    /* execute block before or after calling to dismiss modal view */ 
    [self dismissPresentingModalViewController:modalView animated:animated]; 
    //block(); 
} 
- (void)modalViewDissapeared:(id)modalView 
{ 
    if ([modalView isKindOfClass:[ModalViewController class]]) { 
     NSLog(@"Do stuff based on class."); 
    } 
} 
- (void)executeBlockOnModalDissapearance: (void(^)())block 
{ 
    block(); 
    NSLog(@"This delay's dealloc on modal view until block completes"); 
} 
@end 

ModalViewController.m

#import "ModalViewController.h" 
@implementation ModalViewController 
@synthesize presentorDelegate; 

- (void)close 
{ 
    if (1 == 0 /*need to do something before dealloc*/){ 
     [self.presentorDelegate dismissPresentingModalViewController:self animated:YES withBlock:^{ 
      NSLog(@"Do stuff with block. Save, animate, etc"); 
     }]; 

    } else { 
     [self.presentorDelegate dismissPresentingModalViewController:self animated:YES]; 
    } 
} 

- (void)viewDidDisappear:(BOOL)animated 
{ 
    if (1 == 0 /*stuff to do*/){ 
     [self.presentorDelegate executeBlockOnModalDissapearance:^{ 
     // do stuff before modal view is deallocated 
     }]; 
    } 
    [self.presentorDelegate modalViewDissapeared:self]; 

    presentorDelegate = nil; 
    [super viewDidDisappear:animated]; 
} 
@end; 
0
// present modal view inside another presented modal view 

    FirstViewController *firstVC = [[FirstViewController alloc] initWithNibName:@"FirstViewController" bundle:nil]; 
    UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController: firstVC]; 

    // Note: you can use your viewcontroller instead self.window.rootViewController 

    [self.window.rootViewController presentViewController:navController animated:YES completion:^{ 
       //code... 
        SecondViewController *secondVC = [[SecondViewController alloc] initWithNibName:@"SecondViewController" bundle:nil]; 

        [navController presentViewController: secondVC animated:YES completion:nil]; 

       } 
      }]; 
Verwandte Themen