iOS 7: пользовательский контроллер представления контейнера с UINavigationController в качестве дочернего контроллера представления

Я хотел бы написать собственный полноэкранный контроллер представления контейнера с намерением поместить в него UINavigationController в качестве дочернего контроллера представления. Представление UINavigationController заполнит представление контроллера представления контейнера, так что похоже, что UINavigationController является корневым контроллером представления. (Можно захотеть сделать что-то подобное, скажем, для создания пользовательского интерфейса скользящей боковой панели, популярного в Facebook.)

То, что я сделал, работает, за исключением того, что при представлении другого контроллера представления возникает сбой, который скрывает строку состояния, когда iPhone находится в горизонтальной ориентации. Как правило, панель навигации перемещается вверх, когда строка состояния исчезает, и скользит вниз, когда она появляется снова. Вместо этого панель навигации остается там, где она находится, когда предполагается, что она должна скользить вверх, и когда она должна скользить вниз, она сначала позиционируется с перекрывающейся над ней строкой состояния, а затем переходит на правильную позицию ниже строки состояния. По сути, я пытаюсь заставить UINavigationController вести себя так, как если бы он не находился внутри пользовательского контроллера представления контейнера.

Ниже приведен код, который вы можете запустить, чтобы увидеть проблему, но если вы не хотите этого делать, просто посмотрите наContainerViewController класс, который реализует минимальный пользовательский контроллер представления контейнера.Чего мне не хватает в моем собственном контроллере представления контейнера, который вызывает эту проблему? Это работает, когда я использую UITabBarController в качестве контроллера представления контейнера, поэтому мне кажется, что я просто что-то упустил в своей реализации.

БОЛЬШЕ ЧЕЛОВЕКА, НИЖЕ ЧИТАТЬ, ЕСЛИ ВЫ ХОТИТЕ

Если вы хотите запустить пример кода, чтобы увидеть проблему, вот обзор. Существует определение препроцессора под названиемРЕЖИМ определяется вAppDelegate условно скомпилировать приложение тремя способами.

когдаРЕЖИМ == 1, ViewController находится внутри UINavigationController. Затем вы можете нажать кнопку «Представить», чтобы представитьViewControllerWithStatusBarHidden, а затем вы можете нажать кнопку «Отклонить», чтобы закрыть этот вид контроллера. Этот режим приложения показывает поведение, которое я ищу.

когдаРЕЖИМ == 2мы имеем то же самое, что и вРЕЖИМ == 1 за исключением того, что UINavigationController находится внутриContainerViewController, Этот режим приложения показывает нежелательное поведение, которое я имею в настоящее время.

когдаРЕЖИМ == 3мы имеем то же самое, что и вРЕЖИМ == 1 за исключением того, что UINavigationController находится внутри UITabBarController. Этот режим приложения показывает, что возможно получить поведение, которое я ищу.

Опять же, чтобы увидеть проблему, просто нажмите кнопку «Настоящее время», а затем кнопку «Отклонить», когда iPhone находится в альбомной ориентации.

КОД

Четыре класса:

ContainerViewControllerAppDelegateViewControllerViewControllerWithStatusBarHidden

ContainerViewController.h

#import <UIKit/UIKit.h>

@interface ContainerViewController : UIViewController

@property (nonatomic) UIViewController * viewController;

@end

ContainerViewController.m

#import "ContainerViewController.h"

// This custom container view controller only has one child view controller,
// whose view fills up the view of the container view controller.
@implementation ContainerViewController

- (UIViewController *)viewController {
    if (self.childViewControllers.count > 0) {
        return [self.childViewControllers firstObject];
    }
    else {
        return nil;
    }
}

- (void)setViewController:(UIViewController *)viewController {
    UIViewController *previousViewController = [self.childViewControllers firstObject];
    if ((previousViewController == nil && viewController != nil)
        || (previousViewController != nil && viewController == nil)
        || (previousViewController != nil && viewController != nil
            && previousViewController != viewController))
    {
        if (previousViewController != nil) {
            // Remove the old child view controller.
            [previousViewController willMoveToParentViewController:nil];
            [previousViewController.view removeFromSuperview];
            [previousViewController removeFromParentViewController];
        }

        if (viewController != nil) {
            // Add the new child view controller.
            [self addChildViewController:viewController];
            self.viewController.view.frame = self.view.bounds;
            self.viewController.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
            [self.view addSubview:self.viewController.view];
            [self.viewController didMoveToParentViewController:self];
        }
    }
}

- (UIViewController *)childViewControllerForStatusBarHidden {
    return self.viewController;
}

- (UIViewController *)childViewControllerForStatusBarStyle {
    return self.viewController;
}

@end

AppDelegate.h

#import <UIKit/UIKit.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@end

AppDelegate.m

#import "AppDelegate.h"

#import "ViewController.h"
#import "ContainerViewController.h"

#define MODE 2  // Mode can be 1, 2, or 3.

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

    ViewController *vc = [[ViewController alloc] initWithNibName:nil bundle:nil];
    UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc];

#if MODE == 1   // No container view controller.

    self.window.rootViewController = nav;

#elif MODE == 2 // Use custom container view controller.

    ContainerViewController *container = [[ContainerViewController alloc] initWithNibName:nil bundle:nil];
    container.viewController = nav;
    self.window.rootViewController = container;

#elif MODE == 3 // Use tab bar controller as container view controller.

    UITabBarController *tab = [[UITabBarController alloc] initWithNibName:nil bundle:nil];
    tab.viewControllers = @[nav];
    self.window.rootViewController = tab;

#endif

    [self.window makeKeyAndVisible];
    return YES;
}

@end

ViewController.h

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

@end

ViewController.m

#import "ViewController.h"

#import "ViewControllerWithStatusBarHidden.h"

// This view controller will serve as the content of a navigation controller.
// It also provides a button in the navigation bar to present another view controller.
@implementation ViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        self.title = @"Title";
        self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Present"
                                                                                  style:UIBarButtonItemStylePlain
                                                                                 target:self
                                                                                 action:@selector(pressedPresentButton:)];
    }
    return self;
}

- (void)loadView {
    self.view = [[UIView alloc] init];
    self.view.backgroundColor = [UIColor whiteColor];
}

- (void)pressedPresentButton:(id)sender {
    ViewControllerWithStatusBarHidden *vc = [[ViewControllerWithStatusBarHidden alloc] initWithNibName:nil bundle:nil];

    [self presentViewController:vc animated:YES completion:nil];
}

@end

ViewControllerWithStatusBarHidden.h

#import <UIKit/UIKit.h>

@interface ViewControllerWithStatusBarHidden : UIViewController

@end

ViewControllerWithStatusBarHidden.m

#import "ViewControllerWithStatusBarHidden.h"

// This view controller is meant to be presented and does two things:
// (1) shows a button to dismiss itself and (2) hides the status bar.
@implementation ViewControllerWithStatusBarHidden

- (void)loadView {
    self.view = [[UIView alloc] init];
    self.view.backgroundColor = [UIColor yellowColor];
}

- (void)viewDidLoad {
    [super viewDidLoad];

    UIButton *dismissButton = [UIButton buttonWithType:UIButtonTypeSystem];
    [dismissButton setTitle:@"Dismiss" forState:UIControlStateNormal];
    [dismissButton addTarget:self
                      action:@selector(pressedDismissButton:)
            forControlEvents:UIControlEventTouchUpInside];
    dismissButton.frame = CGRectMake(100, 100, 100, 100);

    [self.view addSubview:dismissButton];
}

- (void)pressedDismissButton:(id)sender {
    [self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}

- (BOOL)prefersStatusBarHidden {
    return YES;
}

//- (NSUInteger)supportedInterfaceOrientations {
//    return UIInterfaceOrientationMaskPortrait;
//}

@end

Ответы на вопрос(0)

Ваш ответ на вопрос