简体   繁体   English

iOS根据设备方向切换视图控制器

[英]iOS switching view controllers depending on the device orientation

I'm developing an Augmented Reality application, everything worked properly till now that I need two different kind of visualization (AR and Map) depending on the device orientation. 我正在开发一个增强现实应用程序,到目前为止一切正常,根据设备的方向,我需要两种不同类型的可视化(AR和Map)。 In particular the application should use the landscapeViewController when the device is in landscape mode while it should use another controller (named faceUpViewController ) when the device's orientation is "face up". 特别是当设备处于横向模式时,应用程序应使用landscapeViewController,而当设备的方向为“面朝上”时,应用程序应使用另一个控制器(名为faceUpViewController)。 I tried doing it with two simple view controllers and it works fine. 我试着用两个简单的视图控制器来做,并且工作正常。 The problem happens when the landscapeViewController uses the AR controller. 当landscapeViewController使用AR控制器时,会发生问题。 The view is completely white and I don't understand why. 视图是完全白色的,我不明白为什么。 Both the two controllers are "contained" by a Root View Controller. 这两个控制器均由“根视图控制器”“包含”。 I'm doing everything by coding so without nib files. 我通过编码来完成所有工作,因此没有nib文件。 Here is the code: 这是代码:

RootViewController.m RootViewController.m

- (void)viewDidLoad
{
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange:) name:UIDeviceOrientationDidChangeNotification object:nil];
    [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
}

- (void)deviceOrientationDidChange:(NSNotification *)notification{

    UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];

    if (orientation == UIDeviceOrientationLandscapeLeft) {
        if (self.landscapeViewController.view.superview == nil) {
            if (self.landscapeViewController == nil) {
                LandscapeViewController *lvc = [[LandscapeViewController alloc] init];
                self.landscapeViewController = lvc;
                [lvc release];
            }
            [self.faceUpViewController.view removeFromSuperview];
            [self.view addSubview:self.landscapeViewController.view];
        }
    }

    if (orientation == UIDeviceOrientationFaceUp) {
        if (self.faceUpViewController.view.superview == nil) {
            if (self.faceUpViewController == nil) {
                FaceUpViewController *fvc = [[FaceUpViewController alloc] init];
                self.faceUpViewController = fvc;
                [fvc release];
            }
            [self.landscapeViewController.view removeFromSuperview];
            [self.view addSubview:self.faceUpViewController.view];
        }
    }

}

@end

LandscapeViewController.m LandscapeViewController.m

// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView
{
    UIView *landscapeView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 1024, 768)];
    landscapeView.backgroundColor = [UIColor yellowColor];
    self.view = landscapeView;
    [landscapeView release];

    ARController *arC = [[ARController alloc] initWithViewController:self];
    arC.landscapeViewController = self;
    self.arController = arC;
    [arC release];
}

//When the view appear present the camera feed
- (void)viewDidAppear:(BOOL)animated { 
    [super viewDidAppear:animated]; 
    [_arController presentModalARControllerAnimated:NO];
}

FaceUpViewController.m FaceUpViewController.m

- (void)loadView
{
    UIView *faceUpView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 1024, 768)];
    faceUpView.backgroundColor = [UIColor blueColor];
    self.view = faceUpView;
    [faceUpView release];
}

ARController.m Very simple version ARController.m非常简单的版本

- (id) initWithViewController:(UIViewController *)theView{

    if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {

        self.rootController = theView; 

        //Retrieve screen bounds
        CGRect screenBounds = [[UIScreen mainScreen] bounds]; 

        UIView *overlaidView = [[UIView alloc] initWithFrame: screenBounds];
        self.overlayView =  overlaidView;
        [overlaidView release];
        self.rootController.view = overlayView;

        // Initialise the UIImagePickerController 
        UIImagePickerController *picker= [[UIImagePickerController alloc] init];
        self.pickerController = picker;
        [picker release];

        self.pickerController.sourceType = UIImagePickerControllerSourceTypeCamera; 
        self.pickerController.cameraViewTransform = CGAffineTransformScale(
                                                                           self.pickerController.cameraViewTransform, 1.0f, 1.12412f);

        self.pickerController.showsCameraControls = NO; 
        self.pickerController.navigationBarHidden = YES; 
        self.pickerController.cameraOverlayView = _overlayView;
    }

    return self;
}

- (void)presentModalARControllerAnimated:(BOOL)animated{
    [self.rootController presentModalViewController:[self pickerController] animated:animated]; 
    self.overlayView.frame = self.pickerController.view.bounds;
}

@end

I say again that I'm doing everything by coding thereby without nib files. 我再说一次,我正在通过没有nib文件的编码来做所有事情。 I really appreciate any advice! 我真的很感谢任何建议! Thanks 谢谢

The primary problem with adding and removing your "child" view controllers' views as you've done here is that the view controller life cycle methods ( viewWillAppear: , viewDidAppear: , etc.) won't ever get called on your child view controllers. 像这里所做的那样,添加和删除“子”视图控制器的视图的主要问题是视图控制器生命周期方法( viewWillAppear:viewDidAppear:等)永远不会在子视图控制器上调用。 Containers like UINavigationController and UITabBarController have always known how to delegate methods like these appropriately to their children, but UIViewController didn't officially support the ability to nest view controllers under your own custom container before iOS 5. It was possible, but it took a lot more work to do it right. 诸如UINavigationControllerUITabBarController类的容器一直都知道如何将此类方法适当地委派给他们的孩子,但是UIViewController并没有正式支持在iOS 5之前将视图控制器嵌套在您自己的自定义容器中的功能。这是可能的,但是这花费了很多做正确的更多工作。

If you want to stick with the approach of adding and removing subviews, you have two options: 如果要坚持添加和删除子视图的方法,则有两个选择:

  1. Require iOS 5+, and call addChildViewController: , removeFromParentViewController , transitionFromViewController:toViewController:duration:options:animations:completion: , willMoveToParentViewController: , and didMoveToParentViewController: as described in the Implementing a Container View Controller section of the UIViewController Class Reference. 需要iOS 5以上版本,并按照UIViewController类参考的“ 实现容器视图控制器”部分中的描述,调用addChildViewController:removeFromParentViewControllertransitionFromViewController:toViewController:duration:options:animations:completion:willMoveToParentViewController:didMoveToParentViewController:

  2. To support older iOS versions, you'll have to override many of the methods of the UIViewController class and delegate those calls manually to your child view controllers to make them behave as expected. 为了支持较旧的iOS版本,您必须重写UIViewController类的许多方法,并将这些调用手动委派给子视图控制器,以使它们的行为符合预期。 I'd pay particular attention to the sections titled, "Responding to View Events", and "Responding to View Rotation Events" in the UIViewController Class Reference. 我将特别注意UIViewController类参考中标题为“响应视图事件”和“响应视图旋转事件”的部分。

A different approach for pre-iOS 5 support is to present your child view controllers using presentModalViewController:animated: rather than adding their views as subviews to a container. 支持iOS 5之前版本的另一种方法是使用presentModalViewController:animated:显示子视图控制器,而不是将其视图作为子视图添加到容器中。 Apple describes this approach in the View Controller Programming Guide for iOS under the section, Creating an Alternate Landscape Interface . Apple在《适用于iOS的View Controller编程指南》下的创建备用横向界面一节中介绍了这种方法。 The advantage of this approach is that your child view controllers are officially supported as first-class members of the view controller hierarchy, so UIKit will automatically manage their life cycles appropriately. 这种方法的优点是,您的子视图控制器作为视图控制器层次结构的一等成员而得到正式支持,因此UIKit将自动适当地管理其生命周期。 You won't have to override and delegate all those methods manually. 您不必手动覆盖和委派所有这些方法。

You might want to try getting your acceptance rate up a little bit - more people would be willing to help you. 您可能希望尝试提高接受率-更多的人愿意帮助您。

Anyway, wild guess: in your root controller, try putting the contents of 无论如何,大胆的猜测:在您的根控制器中,尝试将

  deviceOrientationDidChange

into 进入

  deviceOrientationWillChange.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM