我想编写一个自定义的全屏容器视图控制器,目的是将 UINavigationController 作为子视图控制器放入其中。UINavigationController 的视图将填满容器视图控制器的视图,因此它看起来就像 UINavigationController 是根视图控制器。(比如说,创建由 Facebook 普及的滑动侧边栏菜单 UI。)
我所做的工作除了在呈现另一个视图控制器时出现故障,当 iPhone 处于横向时隐藏状态栏。通常,导航栏在状态栏消失时向上滑动,在再次出现时向下滑动。相反,导航栏在它应该向上滑动时停留在原位,当它应该向下滑动时,它首先与状态栏重叠定位,然后跳转到状态栏下方的正确位置。基本上,我试图让 UINavigationController 的行为与它不在自定义容器视图控制器内时一样。
下面是一些您可以运行以查看问题的代码,但如果您不想这样做,只需查看ContainerViewController类,它实现了一个最小的自定义容器视图控制器。导致此问题的自定义容器视图控制器中缺少什么?当我使用 UITabBarController 作为容器视图控制器时它可以工作,所以看起来我只是在我的实现中遗漏了一些东西。
如果您愿意,可以阅读以下更多内容
如果您想运行示例代码来查看问题,这里有一个概述。AppDelegate中定义了一个名为MODE的预处理器定义,以三种方式有条件地编译应用程序。
当MODE == 1时,ViewController位于 UINavigationController 中。然后您可以按“Present”按钮来展示ViewControllerWithStatusBarHidden,然后您可以按“Dismiss”按钮来关闭此视图控制器。应用程序的这种模式显示了我正在寻找的行为。
当MODE == 2时,除了 UINavigationController 位于ContainerViewController内部之外,我们与MODE == 1中的情况相同。该应用程序的这种模式显示了我目前的不良行为。
当MODE == 3时,除了 UINavigationController 位于 UITabBarController 内部之外,我们与MODE == 1中的情况相同。该应用程序的这种模式表明可以获得我正在寻找的行为。
同样,要查看问题,只需在 iPhone 处于横向时按“呈现”按钮,然后按“关闭”按钮。
代码
四类:
- 容器视图控制器
- 应用委托
- 视图控制器
- ViewControllerWithStatusBarHidden
ContainerViewController.h
#import <UIKit/UIKit.h>
@interface ContainerViewController : UIViewController
@property (nonatomic) UIViewController * viewController;
@end
容器视图控制器.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
视图控制器.h
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
视图控制器.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