Posiadanie UINavigationController w widoku głównym UISplitViewController w systemie iOS 8

W moim UISplitViewController, widok główny jest kontrolerem UINavigationController zawierającym Kontroler UITableViewController. Czasami, gdy użytkownik wybierze element w tabeli, muszę wypchnąć inny kontroler tableViewController nad istniejącą tabelę w widoku głównym.

W iOS 7, w moim pierwszym UITableViewController po prostu wywołuję

[self.navigationController pushViewController:otherTableVC animated:YES];

W iOS 8:

Gdy rozdzielony widok jest zwinięty, otherTableVC staje się widokiem szczegółów! Następnie po obróceniu urządzenia widzimy dwie tabele obok siebie...

Co gorsza, jeśli urządzenie pokazuje dwa panele, kod działa świetnie, a druga tabela jest przesuwana nad pierwszą w widoku głównym. Ale po podwójnym obrocie, dwa stoły są ponownie obok siebie. Wygląda na to, że zwinięty tryb UISplitViewController zakłóca mój własny Kontroler nawigacyjny...

Jak mogę zarządzać własnym kontrolerem UINavigationController w widoku głównym?

Dziękuję

EDITED:

Moje zarówno podstawowe jak i szczegóły widoki mają Kontroler nawigacji. Aby rozwiązać mój problem, odkryłem, że w trybie zwiniętym muszę stworzyć dodatkowy Kontroler nawigacyjny i przesunąć go nad głównym kontrolerem nawigacyjnym.

UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:otherTableVC];
[self.navigationController pushViewController:navController animated:YES];
Odkryłem, że możemy wcisnąć Kontroler nawigacyjny do innego kontrolera nawigacyjnego.
Author: PatrickV, 2014-09-26

1 answers

Krótka odpowiedź, możesz kontrolować to zachowanie za pomocą metod UISplitViewControllerDelegate:

splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:
splitViewController:separateSecondaryViewControllerFromPrimaryViewController:

Podejrzewam, że to, co naprawdę chcesz zrobić, to poradzić sobie z sytuacją, w której masz aplikację opartą na iOS 8 UISplitViewController, w której główne i szczegółowe widoki są zarówno UINavigationControllers, jak i istnieją pewne kontrolery viewControllers (w tych kontrolerach nawigacyjnych), które chcesz wyświetlać tylko po stronie głównej lub szczegółowej podzielonego widoku. Odpowiedź poniżej dotyczy tego. Informatyka radzi sobie również z sytuacją, w której czasami chcesz, aby Widok zastąpił widoki w kontrolerze nawigacji szczegółowej, a nie został tam pchnięty.

Małe zastrzeżenie: poniższy kod Nie dotyczy wszystkich możliwych przypadków i ma pewne założenia:

  • nie spodziewamy się, że cokolwiek może się zmienić na stosie kontrolerów nawigacji szczegółowej, gdy rozdzielony Widok zostanie zwinięty, a widoki te zostaną zasłonięte przez szczegółowy widok nad nimi.
  • nasze podklasy UIViewController wszystkie mają właściwość shouldDisplayInDetailedView i shouldReplaceDetailedView
  • Zakładamy, że wypychamy widoki tylko do kontrolera nawigacji szczegółowej, który ma ustawioną właściwość shouldDisplayInDetailedView.
  • Kontrolery widoku są dodawane do strony szczegółów poprzez splitViewController:showDetailViewController: lub pushViewController:animated: we właściwości navigationController widoku szczegółowego (w stanie rozwiniętym lub zwiniętym).
  • Kontrolery widoku to powinno zastąpić Kontrolery widoku w kontrolerze nawigacyjnym Detail są dodawane tylko przez splitViewController: showDetailViewController: i tylko z interakcji z widokiem w głównym kontrolerze widoku, tzn. może się to zdarzyć tylko wtedy, gdy główny kontroler widoku nie jest zasłonięty, gdy jest w stanie zwiniętym.
  • mamy BlankViewController do wyświetlenia w widoku szczegółów, gdy kontroler dzielonego widoku zostanie rozszerzony, ale mamy tylko Kontrolery widoku, które powinny pozostać na Strona główna.

Nie polecam implementacji tylko jednej strony splitViewController:collapseSecondaryViewController:ontoPrimaryViewController: / splitViewController: separateSecondaryViewControllerFromprimaryviewcontroller: logiczne i w zależności od domyślnej implementacji dla drugiej strony. Apple robi dziwne rzeczy, takie jak umieszczenie kontrolera Uinavigationviewcontroller od strony szczegółów do strony głównej jako jednego z kontrolerów ViewController w głównym kontrolerze nawigacyjnym stos, ale potem wciskając nad nim inne kontrolery widoku, które nawet jeśli całkowicie rozumiesz, nadal nie mogą być replikowane z własnego kodu. Dlatego najlepiej jest samodzielnie obsługiwać obie strony procesu.

Tego używam:

#pragma mark -
#pragma mark Split View Controller delegate.

- (BOOL)splitViewController:(UISplitViewController *)splitViewController showViewController:(UIViewController *)vc sender:(id)sender
{
    //Standard behaviour.  This won't get called in our case when the split view is collapsed and the primary view controllers are obscured.
    return NO;
}

// Since we treat warnings as errors, silence warning about unknown selector below on UIViewController subclasses.
#pragma GCC diagnostic ignored "-Wundeclared-selector"


- (BOOL)splitViewController:(UISplitViewController *)splitViewController showDetailViewController:(UIViewController *)vc sender:(id)sender
{
    if (splitViewController.collapsed == NO)
    {
        // The navigation controller we'll be adding the view controller vc to.
        UINavigationController *navController = splitViewController.viewControllers[1];

        UIViewController *topDetailViewController = [navController.viewControllers lastObject];
        if ([topDetailViewController isKindOfClass:[BlankViewController class]] ||
           ([vc respondsToSelector:@selector(shouldReplaceDetailedView)] && [vc performSelector:@selector(shouldReplaceDetailedView)]))
        {
            // Replace the (expanded) detail view with this new view controller.
            [navController setViewControllers:@[vc] animated:NO];
        }
        else
        {
            // Otherwise, just push.
            [navController pushViewController:vc animated:YES];
        }
    }
    else
    {
        // Collapsed.  Just push onto the conbined primary and detailed navigation controller.
        UINavigationController *navController = splitViewController.viewControllers[0];
        [navController pushViewController:vc animated:YES];
    }

    // We've handled this ourselves.
    return YES;
}

- (BOOL)splitViewController:(UISplitViewController *)splitViewController collapseSecondaryViewController:(UIViewController *)secondaryViewController ontoPrimaryViewController:(UIViewController *)primaryViewController
{
    UINavigationController *primaryNavController = (UINavigationController *)primaryViewController;
    UINavigationController *secondaryNavController = (UINavigationController *)secondaryViewController;
    UIViewController *bottomSecondaryView = [secondaryNavController.viewControllers firstObject];
    if ([bottomSecondaryView isKindOfClass:[BlankViewController class]])
    {
        NSAssert([secondaryNavController.viewControllers count] == 1, @"BlankViewController is not only detail view controller");
        // If our secondary controller is blank, do the collapse ourself by doing nothing.
        return YES;
    }

    // We need to shift these view controllers ourselves.
    // This should be the primary views and then the detailed views on top.
    // Otherwise the UISplitViewController does wacky things like embedding a UINavigationController inside another UINavigation Controller, which causes problems for us later.
    NSMutableArray *newPrimaryViewControllers = [NSMutableArray arrayWithArray:primaryNavController.viewControllers];
    [newPrimaryViewControllers addObjectsFromArray:secondaryNavController.viewControllers];
    primaryNavController.viewControllers = newPrimaryViewControllers;

    return YES;
}

- (UIViewController *)splitViewController:(UISplitViewController *)splitViewController separateSecondaryViewControllerFromPrimaryViewController:(UIViewController *)primaryViewController
{
    UINavigationController *primaryNavController = (UINavigationController *)primaryViewController;

    // Split up the combined primary and detail navigation controller in their component primary and detail view controller lists, but with same ordering.
    NSMutableArray *newPrimaryViewControllers = [NSMutableArray array];
    NSMutableArray *newDetailViewControllers = [NSMutableArray array];
    for (UIViewController *controller in primaryNavController.viewControllers)
    {
        if ([controller respondsToSelector:@selector(shouldDisplayInDetailedView)] && [controller performSelector:@selector(shouldDisplayInDetailedView)])
        {
            [newDetailViewControllers addObject:controller];
        }
        else
        {
            [newPrimaryViewControllers addObject:controller];
        }
    }

    if (newDetailViewControllers.count == 0)
    {
        // If there's no detailed views on the top of the navigation stack, return a blank view  (in navigation controller) for detailed side.
        UINavigationController *blankDetailNavController = [[UINavigationController alloc] initWithRootViewController:[[BlankViewController alloc] init]];
        return blankDetailNavController;
    }

    // Set the new primary views.
    primaryNavController.viewControllers = newPrimaryViewControllers;

    // Return the new detail navigation controller and views.
    UINavigationController *detailNavController = [[UINavigationController alloc] init];
    detailNavController.viewControllers = newDetailViewControllers;
    return detailNavController;
}
 24
Author: Michael Wybrow,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-08 08:54:00