2010-04-21 5 views
9

Ho due visualizzazioni che devono essere visualizzate modalmente, una dopo l'altra. Questo non funziona se si chiude e si visualizza consecutivamente, in questo modo:Modo corretto di mostrare le viste modali consecutive

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

La seconda vista modale semplicemente non viene visualizzata.

ho visto una correzione che è stato qualcosa di simile:

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

Il problema è che questo non funzionerà per tutto il tempo (il ritardo necessario è superiore, a volte).

Un'altra possibile soluzione potrebbe essere quella di eliminare l'animazione:

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

ma mi piacerebbe davvero mantenere l'animazione, per mantenere la sensazione che il primo modale è fuori strada. Eventuali suggerimenti?

+3

Perché non usare modale View Controller che cambia il suo punto di vista? Due controller modali in fila sarebbero un po 'fastidiosi. – bpapa

+0

Se sono "consecutivi", considera l'utilizzo della navigazione. –

+0

Sei sicuro al 100% che le revisioni della prima vista modale e l'apertura della seconda sono entrambe eseguite nel contesto della discussione principale? – yonel

risposta

17

EDIT: Il meccanismo "corretta" per fare questo in iOS5 + sarebbe quella di utilizzare il metodo – dismissViewControllerAnimated:completion:, e presenta al controllore vista sequenziale dal blocco completamento.


Il viewcontroller che viene mostrato modale avrà il suo viewDidDisappear: animato: metodo chiamato una volta modale-rigetto-animazione è completa.AFIK questo è l'unico posto che puoi collegare per avviare un successivo presentModalViewController: animated: call.

Ho una classe che uso per presentare i controllori di visualizzazione modali e implementa la logica che stai cercando tramite una richiamata al controller di visualizzazione presentando una volta che il licenziamento è completo. Per utilizzare questa classe, basta allocare/avviare un'istanza e presentarla utilizzando il normale presentViewController: animato: chiamata. Implementare il seguente metodo sul controller della vista presentazione:

- (void) modalViewControllerDidDismiss:(UIViewController *)modalViewController 

Questo sarà chiamato immediatamente il controller di vista modale è andato, ed è possibile presentare un nuovo controller di vista modale in questo momento.

Una cosa bella - poiché questa classe è una specializzazione di UINavigationController, puoi configurare la barra di navigazione on/off come preferisci. La classe ha anche una logica incorporata per mostrare un pulsante di espulsione, come preferisci.

Ecco la definizione della classe:

@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 

E l'implementazione della classe:

@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 

e, ecco come si può utilizzare (nel contesto di qualche normale controller della vista):

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

e, ecco il metodo callback di licenziamento, che presenta un nuovo controller di visualizzazione modale:

- (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 può sapere quando l'ultimo controller di visualizzazione modale su di esso è scomparso perché riceverà una viewDidAppear :. Hai provato a collegare il presentModalViewController: del controller di visualizzazione successivo a quello?

+0

Si verificano ancora problemi di temporizzazione ... viewDidAppear viene chiamato prima che la vista sia effettivamente apparsa, apparentemente. –

+0

C'è sempre 'performSelector: foo afterDelay: 0' che potrebbe funzionare in viewDidAppear ... –

0

Se si desidera concatenare più animazioni di viste multiple, in realtà suggerirei di gestire da soli la logica di animazione. Non è troppo complicato, e quindi puoi avere un controllo preciso su come vengono presentate le visualizzazioni. Ho appena scritto qualcosa di simile per un'altra domanda qui:

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

Si può solo animare la vista, animare la vista fuori, e quando il selettore di animationDidStop si chiama, animato tua seconda vista. La bella parte di questo è che puoi anche giocare con l'opacità della vista e la direzione dell'animazione, così come decidere esattamente quando devono apparire le viste. Ad esempio, potresti avere la seconda vista che scorre verso l'alto sulla prima vista mentre la prima vista sta scivolando via; non c'è bisogno di aspettare che il primo completi la sua animazione.

+0

Idea interessante. Sembra che questo ti costringa ad uscire da MVC, no? Come se finissi con due visualizzazioni e un controller. –

+0

MVC non significa necessariamente uno di ciascuno; si tratta davvero di separare questi componenti gli uni dagli altri e lasciare che ciascuno faccia la propria parte. In realtà è abbastanza comune per un controller di visualizzazione gestire più viste. Dopo tutto, molti/la maggior parte dei componenti dell'interfaccia utente che si aggiungono alla vista di un controller di visualizzazione (pulsanti, immagini, ecc.) E animati sono solo visualizzazioni. È meglio pensare a ciascun controller di visualizzazione come a rappresentare un blocco a schermo intero del programma e il cervello dietro quella sezione dell'app. Il controller è la logica che collega il (i) modello (i) e le viste (i) insieme. – atticus

0

Il problema è relativo a "mostra una vista modale all'interno di una vista modale"? Ho inserire una domanda su questo qui: iPhone modal view inside another modal view?

+0

Non proprio. Si tratta di chiudere una vista modale e aprirne un'altra. iOS sembra soffocare quando chiudi e presenta una vista troppo ravvicinata. Questo è particolarmente un problema con il selezionatore di telecamere, perché ha un notevole carico/tempo di scaricamento. Se si desidera ignorare il selezionatore della fotocamera e mostrare qualcos'altro, è possibile imbattersi in tutti i tipi di comportamenti strani. –

0

La soluzione migliore che ho trovato qualcosa di simile (se sono tutti i bambini pari della vista padre) è di rattoppare il loro parere su un UIScrollView con paginazione abilitato, (è possibile aggiungere un controllo di pagina in basso per renderlo chiaro e per la navigazione) quindi aggiungere le visualizzazioni dei controller alla visualizzazione della pagina man mano che vengono visualizzate sullo schermo, rimosse man mano che si spostano fuori schermo.

Potrebbe anche essere necessario chiamare fittamente -viewWillAppear e -viewWillDisappear se i controller si affidano a questo nome. Sembra una specie di hack-ish quando stai codificando tutto, ma una volta che lo hai funzionato sembra liscio e naturale, e non c'è nessuna attesa associata all'animazione di una vista, quindi l'animazione successiva in una volta è andato.

0

trovo usando -viewDidDissapear della vista modale per richiamare i metodi per la vista presentazione del lavoro di controllo molto bene. Un vantaggio è la possibilità di ritardare la deallocazione sul controller della vista modale. Si prega di postare eventuali miglioramenti che posso fare. La mia ispirazione per la creazione di questo protocollo è venuta da iOS 5 "dismissViewControllerAnimated: completion:" oltre a UIViewController. Volevo questa funzionalità 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]; 

       } 
      }]; 
Problemi correlati