2010-04-21 14 views
9

Mam dwa widoki, które muszą być wyświetlane modalnie, jeden po drugim. Nie działa to, jeśli odrzucamy i wyświetlamy kolejno:Prawidłowy sposób wyświetlania kolejnych widoków modalnych

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

Drugi widok modalny po prostu się nie pokazuje.

Widziałem poprawkę, że było coś takiego:

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

Problem polega na tym, że to nie będzie działać cały czas (opóźnienie potrzebne jest lepsze, czasami).

Innym możliwym fix byłoby wyeliminować animację:

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

Ale naprawdę chciałbym zachować animację, aby utrzymać wrażenie, że pierwszy modalna jest na uboczu. Jakieś sugestie?

+3

Dlaczego nie wystarczy użyć na Modal View Controller, który zmienia swój pogląd? Dwa kontrolery widoku modalnego z rzędu byłyby trochę denerwujące. – bpapa

+0

Jeśli są "następujące po sobie", rozważ użycie nawigacji. –

+0

Czy jesteś w 100% pewien, że odrzucenie pierwszego widoku modalnego i otwarcie drugiego są wykonywane w kontekście głównego wątku? – yonel

Odpowiedz

17

Edycja: „prawidłowy” mechanizm zrobić w iOS5 + byłoby użyć metody – dismissViewControllerAnimated:completion: i przedstawia sekwencyjnego sterowania widok z bloku realizacji.


viewcontroller który jest pokazany modalne, będzie mieć swoje viewDidDisappear: animowany: metoda zwana po modalnym zwolnienie animacja jest zakończona.AFIK to jedyne miejsce, w które można podpiąć, by zainicjować kolejny presentModalViewController: animated: call.

Mam klasę, której używam do prezentacji modalnych kontrolerów widoku i implementuje logikę, której szukasz, przez wywołanie zwrotne do prezentującego kontrolera widoku po zakończeniu zwolnienia. Aby użyć tej klasy, po prostu przydzielaj/init instancję i prezentuj przy użyciu zwykłego presentViewController: animated: call. Wdrożenie następującą metodę na kontrolerze widoku prezentowanie:

- (void) modalViewControllerDidDismiss:(UIViewController *)modalViewController 

To będzie nazywany naraz modalna kontroler widok zniknął, a można przedstawić nowy kontroler modalne widoku w tym czasie.

Jedną miłą rzeczą zbyt - ponieważ ta klasa jest specjalizacja UINavigationController można skonfigurować navigationBar on/off, jak chcesz. Klasa ma również wbudowaną logikę, która pokazuje przycisk odrzucania, tak jak lubisz.

Oto definicja klasy:

@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 

i wdrożenie klasa:

@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 

, a oto jak można go używać (w kontekście jakiegoś normalnego widoku kontrolera):

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

i tutaj jest metoda wywołania zwrotnego, która przedstawia nowy kontroler widoku modalnego:

- (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 może stwierdzić, kiedy ostatni z kontrolerów widoku modalnego na nim zniknął, ponieważ otrzyma viewDidAppear :. Czy próbowałeś powiązać presentModalViewController: kolejnego kontrolera widoku do tego?

+0

Nadal napotykasz problemy z zegarem ... viewDidAppear jest wywoływany, zanim widok rzeczywiście się pojawił. –

+0

Zawsze jest 'performSelector: foo afterDelay: 0', który może działać w viewDidAppear ... –

0

Jeśli naprawdę chcesz połączyć wiele animacji widoku, proponuję, abyś sam obsługiwał animację. Nie jest to zbyt trudne, a następnie możesz mieć szczegółową kontrolę nad sposobem prezentacji poglądów. Właśnie napisał coś podobnego do innego pytanie tutaj:

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

Można tylko animować pogląd na temat, animować widoku off, a gdy selektor animationDidStop nazywa, animowane swój pogląd na drugą. Przyjemną częścią tego jest możliwość gry z przezroczystością widoku i kierunkiem animacji, a także dokładne określenie, kiedy mają się pojawiać. Na przykład możesz mieć drugi widok przesuwający się nad pierwszym widokiem, ponieważ pierwszy widok się ślizga; nie trzeba czekać na zakończenie pierwszej animacji.

+0

Interesujący pomysł. Wygląda na to, że to zmusza cię do wyjścia z MVC, prawda? Jakbyś skończył z dwoma widokami i jednym kontrolerem. –

+0

MVC nie musi oznaczać po jednym; chodzi o oddzielenie tych elementów od siebie i umożliwienie każdemu wykonania własnej roli. Często jeden kontroler widoku obsługuje wiele widoków. W końcu wiele/większość komponentów UI dodawanych do widoku kontrolera widoku (przyciski, obrazy itp.) I animacja są tylko widokami. Lepiej jest myśleć o tym, że każdy kontroler widoku reprezentuje jeden pełnoekranowy fragment programu i mózg za tą sekcją aplikacji. Kontroler jest logiką, która łączy model (y) i widoki (s) razem. – atticus

0

Czy Twój problem jest związany z "pokazaniem widoku modalnego wewnątrz widoku modalnego"? mam po odpowiedzi na ten temat tutaj: iPhone modal view inside another modal view?

+0

Niezupełnie. Chodzi o zamknięcie jednego widoku modalnego i otwarcie drugiego. Wydaje się, że system iOS dławi się, gdy zamkniesz widok i przedstawisz go zbyt blisko siebie. Jest to szczególnie problem z selektorem kamer, ponieważ ma duży czas ładowania/rozładowania. Jeśli chcesz odrzucić wybór kamer i pokazać coś innego, możesz natknąć się na dziwne zachowanie. –

0

Najlepszym rozwiązaniem znalazłem czegoś takiego (jeśli wszystkie są równe dzieci widoku macierzystego) ma załatać swoje poglądy na w UIScrollView z stronicowania włączone, (możesz dodać kontrolkę strony u dołu, aby było jasne i dla nawigacji), a następnie dodaj widoki kontrolerów do widoku strony, gdy pojawią się na ekranie, usuń, gdy wychodzą poza ekran.

Możliwe, że będziesz musiał również wykonać fałszywe wywołanie -viewWillAppear i -viewWillDisappear, jeśli kontrolery polegają na tym wywołaniu. Czujesz się trochę hack-owski, kiedy kodujesz to wszystko, ale gdy już to zrobisz, wygląda to gładko i naturalnie, i nie ma żadnego oczekiwania związanego z animowaniem jednego widoku, a następnie animowanie następnego w tym samym czasie. przepadło.

0

znajdę użyciu modalnego widoku danych, -viewDidDissapear celu wywołania metod na widoku przedstawianie kontroler praca jest bardzo dobrze. Jedną z korzyści jest możliwość opóźnienia dealokacji na kontrolerze widoku modalnego. Opublikuj wszelkie ulepszenia, które mogę wprowadzić. Moją inspiracją do stworzenia tego protokołu pochodziła z iOS 5 za „dismissViewControllerAnimated: Zakończenie:” dodatek do UIViewController. Chciałem tej funkcji w 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]; 

       } 
      }]; 
Powiązane problemy