4

我想编写一个自定义的全屏容器视图控制器,目的是将 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 处于横向时按“呈现”按钮,然后按“关闭”按钮。

代码

四类:

  1. 容器视图控制器
  2. 应用委托
  3. 视图控制器
  4. 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
4

0 回答 0