iPhone - 处理方向和多视图

4

我花了很长时间努力寻找答案,最终花费了4-5个小时才得以解决。我将回答自己的问题,以便为遇到同样问题的任何人提供支持。

所以,我创建了一个名为Critical Mass Typer的应用程序。它是一款打字游戏,使用键盘作为主要控制方法。单词向屏幕中心移动,在那里你有一个核。你输入单词,并在它到达你的核之前将其击败。如果有4个单词到达你的核,你就会达到临界质量并爆炸(游戏结束)。

现在,我想能够在游戏中支持横向和纵向模式。我事先考虑过,并设计了我的类,使其易于实现。设置游戏来这样做并不是问题。正确旋转视图则是问题所在。

很快出现的一个问题是:任何视图控制器的shouldAutorotateToInterfaceOrientation方法返回NO,都会取消其子视图的返回值。

因此,我的主视图控制器(CriticalMassViewController)控制游戏的启动/菜单,并添加一个运行游戏模式(CMGameViewController)的视图控制器作为子视图。我只希望我的主视图控制器处于横向模式,因为如果我旋转它,动画/按钮都会跑到侧面。如果我想要将其设置为纵向模式,我必须创建另一个视图或更改屏幕上所有内容的位置。然而,我的游戏视图需要能够切换。为了实现这一点,你需要将返回值设置为你希望你的主视图所在的特定模式。然后告诉你的游戏视图不返回任何模式。之后,注册游戏视图以获取通知,然后自己处理旋转。

例如:

CriticalMassViewController.m:

    -(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}

CMGameViewController.m

- (void)viewDidLoad {
    [super viewDidLoad];
    /*GUI setup code was here*/

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didRotate:) name:UIDeviceOrientationDidChangeNotification object:nil];
}

-(void)didRotate:(NSNotification *)nsn_notification {
    UIInterfaceOrientation interfaceOrientation = [[UIDevice currentDevice] orientation];
    /*Rotation Code
    if(interfaceOrientation == UIInterfaceOrientationPortrait) {
        //Portrait setup
    } else if(interfaceOrientation == UIInterfaceOrientationLandscapeRight) {
        //Landscape setup
    }

    */
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
        // Return YES for supported orientations
        return NO; 
    }

好的,这里发生了什么?我的主视图控制器只想保持横屏模式。因此,它会一直保持这种模式,因为它从未注册其他方向进行自动旋转。我的游戏视图控制器需要能够旋转。如果我使用以下代码来处理 shouldAutorotateToInterfaceOrientation

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
        return (interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationLandscapeRight);
    }

当iPhone改变方向时,它不会旋转。这是因为它的父视图表示不想旋转。一旦父视图返回否,子视图甚至都不会被询问。因此,我们游戏视图控制器只需说“不”,我不想自动旋转到任何视图。然后,我们注册通知以便在方向更改时调用自己的旋转方法。
这些代码片段是如何处理自己的旋转的。从didRotate中调用rotateView。请注意,我只希望用户在选择难度后才能旋转,因此我在didRotate方法中有逻辑来确定是否应该旋转。代码中的注释将解释为什么发生某些事情。
-(void) rotateView:(UIInterfaceOrientation)uiio_orientation {

    /*This line is very important if you are using the keyboard. This was actually the
    largest problem I had during this entire ordeal. If you switch orientations while
    the keyboard is already being displayed, it will stay in landscape orientation. To
    get it to switch to portrait, we have to tell the status bar that its orientation
    has changed. Once you do this, the keyboard switches to portrait*/
    [UIApplication sharedApplication].statusBarOrientation = uiio_orientation;

    //Get the view you need to rotate
    UIView *portraitImageView = self.view;

    /*Check to make sure that you are in an orientation that you want to adjust to. If
    you don't check, you can make your view accidently rotate when the user orientates
    their phone to a position you aren't expecting*/
    if(uiio_orientation == UIInterfaceOrientationPortrait || uiio_orientation == UIInterfaceOrientationLandscapeRight) {
        if(uiio_orientation == UIInterfaceOrientationPortrait) {
                    //This transform rotates the view 90 degrees counter clock wise.
            portraitImageView.transform = CGAffineTransformMakeRotation(-M_PI/2);
        } else if(uiio_orientation == UIInterfaceOrientationLandscapeRight) {
                    //This transform rotates the view back to its original position
            portraitImageView.transform = CGAffineTransformMakeRotation(0);
        }

        CGRect frame = portraitImageView.frame;
        frame.origin.y = 0;
        frame.origin.x = 0;
        frame.size.width = portraitImageView.frame.size.height;
        frame.size.height = portraitImageView.frame.size.width;
        portraitImageView.frame = frame;
    }
}

我希望这篇文章能够帮助到一些人,因为我自己在这方面遇到了很大的困难,特别是当键盘从横屏切换到竖屏时。


这条评论与方向无关,但我看了一下你的应用程序,喜欢你在短语“Let's do this!”中使用的字体。那是什么字体类型? - Joo Park
字体名为"刀锋2"(我猜是受到电影的启发)。 - ColdLogic
2个回答

2
用户编写的UIViewControllers不应该嵌套在一个屏幕上。我相信苹果的规定是"每个屏幕只能有一个UIViewController"。像这样的方向改变问题就是其中一个重要原因。这是一个可以理解的"错误",在某些情况下我也会被诱惑使用UIViewController作为UIView加载器。实际上,在屏幕中嵌套或可重用的"小部件"组件中,没有真正的理由使用UIViewController,只是为了获得它的视图,你并不会得到任何好处,因为所有这些有用的便捷函数,如方向更改、viewWillAppear、viewWillDisappear等都不会自动地被任何其他的UIViewController调用!这些调用不是"广播"而是从UIViewController父类传递给UIViewController子类的。如果你编写自己的UIViewController子类,你需要负责传递这些继承方法的调用。
你的内部UIViewController没有被"未调用",因为外部UIViewController回答了NO,而是因为你没有将调用转发给你的嵌套UIViewController。方向更改方法shouldAutorotateToInterfaceOrientation,就像其他的viewWill*方法一样,并不是广播到所有的UIViewControllers,它们是从顶级窗口,从类到类,从层次结构中向下传递的。内置的UIViewControllers,如UINavigationController和UITabBarController,明确地将这些调用传递给它们的子类,这就是为什么当它们到达时,它们似乎像广播一样,但当你插入自己的UINavigationController子类到VC层次结构中时,你必须自己将这些调用传递给任何子级UINavigationController。如果你想编写自己的"全局控制器VC",如UITabBarController替代品,这就是你必须做的。

不好意思,说VC-A/VC-B的话,如果VC-A的方向方法首先被调用并返回“否”,那么就不会调用VC-B的方法。 - ColdLogic
@ColdLogic: http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/AboutViewControllers/AboutViewControllers.html#//apple_ref/doc/uid/TP40007457-CH112-SW12 “不应使用多个自定义视图控制器来管理同一视图层次结构的不同部分。” - user102008
@user102008: 我不...有三个由不同视图控制器管理的单独视图。"您不应该使用多个自定义视图控制器来管理同一视图层次结构的不同部分。同样,您不应该使用一个单独的自定义视图控制器对象来管理多个屏幕的内容。" - ColdLogic
@ColdLogic:但是它们在同一个屏幕上,所以它们在同一层级。 - user102008
@user102008:嗯,iDevices没有多个屏幕,所以它们当然在同一个屏幕上。按照您的逻辑,我们永远不需要超过1个视图控制器。 - ColdLogic
显示剩余3条评论

0
 if([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortrait || [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortraitUpsideDown)
        {         
           //for portrait
             NSLog(@"portrait");
        }
        else if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft || [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeRight)
        {
            // code for landscape orientation      

             NSLog(@"landscape");
        }

为了提高您的帖子质量,请说明您的答案是如何解决问题的。 - Mick MacCallum

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接