2012-08-05 10 views
13

Piszę prostą aplikację, która ma 3 kontrolery widoku. Główny kontroler widoku to podstawowy widok tabeli item listing. Poza tym kontrolerem widoku przepycham dwa różne kontrolery widoku na podstawie interakcji użytkownika - kontrolki widoku lub kontrolera widoku create item.Jak wrócić do kontrolera widoku root, a następnie przejść do innego widoku?

Tak więc scenki wyglądają jak litery V lub coś w tym stylu.

Na moim kontrolerze widoku create item chciałbym, aby powrócił do kontrolera widoku głównego, gdy użytkownik utworzy nowy element, ale następnie przesyła do kontrolera view item, aby móc obejrzeć nowo utworzony element.

Nie mogę sprawić, żeby to zadziałało. Wystarczy, że wrócisz do kontrolera widoku głównego, ale nie mogę przepchnąć tego kontrolera view item.

Wszelkie pomysły? Wkleiłem mój kod, poniżej. Funkcja pop działa, ale nowy widok nigdy się nie pojawia.

- (void) onSave:(id)sender { 

    CLLocation *currentLocation = [[LocationHelper sharedInstance] currentLocation]; 

    // format the thread object dictionary 
    NSArray* location = @[ @(currentLocation.coordinate.latitude), @(currentLocation.coordinate.longitude) ]; 
    NSDictionary* thread = @{ @"title": _titleField.text, @"text": _textField.text, @"author": @"mustached-bear", @"location": location }; 

    // send the new thread to the api server 
    [[DerpHipsterAPIClient sharedClient] postPath:@"/api/thread" 
             parameters:thread 
              success:^(AFHTTPRequestOperation *operation, id responseObject) { 

               // init thread object 
               Thread *thread = [[Thread alloc] initWithDictionary:responseObject]; 

               // init view thread controller 
               ThreadViewController *viewThreadController = [[ThreadViewController alloc] init]; 
               viewThreadController.thread = thread; 

               [self.navigationController popToRootViewControllerAnimated:NO]; 
               [self.navigationController pushViewController:viewThreadController animated:YES]; 

              } 
              failure:^(AFHTTPRequestOperation *operation, NSError *error) { 

               [self.navigationController popToRootViewControllerAnimated:YES]; 

              }]; 

} 
+0

Nie utworzyłbym różnych kontrolerów widoku dla "Utwórz przedmiot" i "Wyświetl przedmiot". Prawdą jest, że możesz chcieć wyświetlić element po jego utworzeniu, ale zawsze istnieje inna możliwość, że użytkownik może chcieć EDYTOWAĆ przedmiot po jego obejrzeniu. Byłoby łatwiej zaprojektować jeden kontroler widoku, aby umożliwić tworzenie, przeglądanie i edytowanie w jednym widoku. Większość aplikacji projektuje je w ten sposób. Zaoszczędź swój czas na segregacji. – Rick

Odpowiedz

6

Łatwym sposobem, aby osiągnąć to, co chcesz zrobić, to zbudować jakąś prostą logikę do głównych kontrolerów widoku root - (void) metodę viewWillAppear i używać wywołania zwrotnego delegata, aby przerzucić przełącznik logiczny. w zasadzie "odwołanie zwrotne" do kontrolera root. oto krótki przykład.

główny sterownik główny (rozważyć ten kontroler A) - dobrze nazwać controllerA ustawić właściwość śledzić status skoku

@property (nonatomic) BOOL jumpNeeded; 

konfigurację pewnej logiki w

- (void)viewWillAppear:(BOOL)animated { 
    [super viewWillAppear:animated]; 
    self.jumpNeeded ? NSLog(@"jump needed") : NSLog(@"no jump needed"); 

    if (self.jumpNeeded) { 
     NSLog(@"jumping"); 
     self.jumpNeeded = NO; 
     [self performSegueWithIdentifier:@"controllerC" sender:self]; 
    } 
} 

Teraz, w Twój główny kontroler główny, gdy wybrany jest wiersz widoku tabeli, wykonaj coś takiego: po naciśnięciu do kontrolera B w tabeli Wyszukałem wybraną metodę

[self [email protected]"controllerB" sender:self]; 

następnie realizować swoje przygotowania do sposobu Segue

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 

    //setup controller B 
    if([segue.identifier isEqualTo:@"controllerB"]){ 
    ControllerB *b = segue.destinationViewController; 
    b.delegate = self; //note this is the back reference 
    } 

    //implement controller c here if needed 
} 

Teraz przechodzimy do controllerB trzeba ustawić właściwość o nazwie „delegat” trzymać tylną odniesienie i trzeba zaimportować plik Główka sterownik główny

#import "controllerA" 

@property (nonatomic,weak) controllerA *delegate; 

następnie tuż przed powrotem do controllerA pop, należy ustawić flagę

self.delegate.jumpNeeded = YES; 
    [self.navigationController popViewControllerAnimated:YES]; 

i to jest o tym. Nie musisz nic robić z kontroleremC. Jest jeszcze kilka innych sposobów, ale jest to całkiem proste do Twoich potrzeb. mam nadzieję, że ci się to uda.

+0

Wybrałem to jako odpowiedź, ponieważ delegaci byli trasą, którą wylądowałem. Mimo, że zrezygnowałem z pchania segmentów razem i poszedłem z modalnym segue, dla widoku 'create item'. – Ryan

+0

Cieszę się, że wskazówki sprawiły, że idziesz w tym kierunku, który pracował dla ciebie. powodzenia! – CocoaEv

0

Nie sądzę, że jest to możliwe, ponieważ cofnięcie się spowolni wszystko.

Myślę, że lepszym sposobem jest umieszczenie danych na modelu singleton, pop na rootviewcontroller i słuchanie muzyki do końca. Następnie sprawdzasz, czy są jakieś dane zapisane w modelu, abyś wiedział, czy powinieneś nacisnąć nowy kontroler viewcontroller.

6

Myślę, że
[self.navigationController pushViewController:viewThreadController animated:YES]; używa innego kontrolera NavigationController niż poprzednia instrukcja. Ponieważ po popping do widoku głównego kontrolera tracisz kontroler nawigacji Jesteś w. Rozwiąż że za pomocą tego kodu zamiast

UINavigationController *nav = self.navigationController; 
[self.navigationController popToRootViewControllerAnimated:NO]; 
[nav pushViewController:viewThreadController animated:YES]; 

Myślę też, że to przyzwyczajenie rozwiązać cały problem. Prawdopodobnie wystąpi błąd informujący, że dwa szybkie popping i pushing mogą unieważnić kontroler NavigationController.
Aby rozwiązać problem, można wcisnąć kontroler NavigationController w metodę viewDidDissPear 2. kontrolera widoku lub wcisnąć go w metodzie viewDidAppear w kontroler widoku głównym (pozycja).

+0

Moje nauki: kiedy używasz animacji: TAK, to nie działa zgodnie z przeznaczeniem, ale animowane: NIE wykonuje zadanie. A ponieważ popToRoot jest krótszy, użyłem tego. Mam nadzieję, że to pomoże! – kjoelbro

+0

Po prostu za pomocą popToRootController jest tutaj odpowiedź wierzę.Nie musisz robić nic śmiesznego ze stosem viewController, a popchnięcia mogą działać normalnie. –

36

Jeśli rozumiem zostanie poprawnie, masz stos widzenia regulatorów:

A (root) - B - C - D - E 

I chcesz go stać:

A (root) - F 

Prawda? W tym przypadku:

NSArray *viewControllers = self.navigationController.viewControllers; 
NSMutableArray *newViewControllers = [NSMutableArray array]; 

// preserve the root view controller 
[newViewControllers addObject:[viewControllers objectAtIndex:0]]; 
// add the new view controller 
[newViewControllers addObject:viewThreadController]; 
// animatedly change the navigation stack 
[self.navigationController setViewControllers:newViewControllers animated:YES]; 
+0

To będzie animować widok E, aby zobaczyć F. –

+2

^@LysannSchlegel, o to chodzi. Animuje się z E-> F, ale jeśli uderzysz w przycisk powrotu, przejdziesz do A zamiast E. Zasadniczo, usuwając tylny stos do widoku rodzica bez żadnych funky/nieoczekiwanych animacji pomiędzy! – DiscDev

+1

Odpowiedź Dave'a jest świetna, przenieś go na wyższy poziom ponownego użycia z kategorią na UINavigationController: http://stackoverflow.com/a/25771209/1103584 – DiscDev

5

Udostępnianie kategorii na UINavigationController na podstawie odpowiedzi Dave DeLong, że używamy w naszej aplikacji, aby przycisk Wstecz zawsze działa zgodnie z wymaganiami.

@implementation UINavigationController (PushNewAndClearNavigationStackToParent) 

- (void) pushNewControllerAndClearStackToParent:(UIViewController*)newCont animated:(BOOL)animated 
{ 
    NSArray *viewControllers = self.viewControllers; 
    NSMutableArray *newViewControllers = [NSMutableArray array]; 
     
    // preserve the root view controller 
    [newViewControllers addObject:[viewControllers firstObject]]; 
    // add the new view controller 
    [newViewControllers addObject:newCont]; 
    // animatedly change the navigation stack 
    [self setViewControllers:newViewControllers animated:animated]; 
} 

@end 
1
NSArray *viewControllers = self.navigationController.viewControllers; 
NSMutableArray *newViewControllers = [NSMutableArray array]; 

// preserve the root view controller 
for(int i = 0; i < [viewControllers count];i++){ 
    if(i != [viewControllers count]-1) 
     [newViewControllers addObject:[viewControllers objectAtIndex:i]]; 
} 
// add the new view controller 
[newViewControllers addObject:conversationViewController]; 
// animatedly change the navigation stack 
[self.navigationController setViewControllers:newViewControllers animated:YES]; 
+0

Czy mógłbyś bardziej rozwinąć swoją odpowiedź, dodając nieco więcej opisu dostarczonego rozwiązania? – abarisone

0

Kiedyś odpowiedź Dave jako inspiracji i uczynił to dla Swift:

let newViewControllers = NSMutableArray() 
newViewControllers.addObject(HomeViewController()) 
newViewControllers.addObject(GroupViewController()) 
let swiftArray = NSArray(array:newViewControllers) as! Array<UIViewController> 
self.navigationController?.setViewControllers(swiftArray, animated: true) 
  1. Wymień HomeViewController() z tym, co chcesz, aby dolny kontroler widoku być
  2. Wymień GroupViewController() z tym, czego chcesz, aby kontroler widoku z góry był
0

Jeśli chcesz nawigować w dowolny sposób w tym samym kontrolerze nawigacyjnym ... możesz uzyskać dostęp do pliku nawigacyjnego A.K.A. viewControllers, a następnie ustaw kontrolery viewcontroller w żądanej kolejności lub dodaj lub usuń niektóre ... To jest najczystszy i natywny sposób na zrobienie tego.

 UINavigationController* theNav = viewControllerToDismiss.navigationController; 
     UIViewController* theNewController = [UIViewController new]; 
     UIViewController* rootView = theNav.viewControllers[0]; 
     [theNav setViewControllers:@[ 
            rootView, 
            theNewController 
            ] animated:YES]; 

wykonaj niezbędne testy, aby uniknąć wyjątków.

Powiązane problemy