iPhone - 使用方向和多视图

时间:2010-07-02 22:17:21

标签: iphone ipad ipod-touch

我长时间努力地搜索,试图解决这个问题。我花了大约4-5个小时才终于找到了解决方案。我将回答我自己的问题,努力为遇到同样问题的任何人提供支持。

所以,我创建了应用程序Critical Mass Typer。这是一种利用键盘作为主要控制方法的打字游戏。单词移向屏幕中央,你有一个核心。你键入单词,然后在它到达你的核心之前把它吹走。如果4个单词进入你的核心,你达到临界质量,然后爆炸(游戏结束)。

现在,我希望能够在游戏中同时支持横向和纵向模式。我提前考虑了它,并设计了我的类,以便它易于实现。设置游戏这样做不是问题。让视图正确旋转是。

有一件事情很快就出现了:任何为视图控制器的shouldAutorotateToInterfaceOrientation方法返回NO的视图都会取消其子视图的返回。

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

对于Ex: 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; 
    }

好的,那么这里发生了什么?我的主视图控制器只想处于LandscapeRight模式。所以它保持这样,因为它从未注册任何其他方向自动旋转。我的游戏视图控制器需要能够旋转。如果我将以下代码用于shouldAutorotateToInterfaceOrientation

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
        return (interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationLandscapeRight);
    }
当IPHONE改变方向时,它不会旋转。这是因为它的超级视图表示它不想旋转。一旦超级视图返回no,则甚至不会询问子视图。所以相反,我们游戏视图控制器只是说不,我不想自动旋转到任何视图。然后我们注册方向更改的通知,并调用我们自己的旋转方法。

这些代码的最后几位是您自己处理旋转的方式。从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;
    }
}

我希望这有助于某人,我知道我有一段非常艰难的时间,特别是键盘从横向到纵向。

2 个答案:

答案 0 :(得分:2)

用户编写的UIViewControllers并不意味着嵌套在一个屏幕上。我相信Apple系列是“每个屏幕一个UIViewController”。像这样的定位变化问题是一个重要原因。这是一个可以理解的“错误”,在某些情况下我很想让自己:在这种情况下,诱惑是使用UIViewController作为UIView加载器。没有任何理由使用UIViewController作为屏幕中的嵌套或可重复使用的“小部件”组件,只是为了获得它的视图,你并没有真正获得任何好处,因为所有这些有用的便利功能,如方向改变,viewWillAppear,viewWillDisappear,除了你自己以外的任何其他UIViewController将为你自动调用 !这些调用不是“广播”,而是从UIViewController父级“转发”到UIViewController子级。如果您编写自己的UIViewController子类,则负责传递任何这些继承的方法调用。

你的内部UIViewController没有“未被调用”,因为外部UIViewController回答NO,因为你没有自己将调用转发到嵌套的UIViewController,所以没有调用它。方向更改方法shouldAutorotateToInterfaceOrientation与其他viewWill *方法一样,不会广播到所有UIViewControllers,它们从顶层窗口向下传递,从类到类。像UINavigationControllers和UITabBarControllers这样的内置UIViewControllers明确地将这些调用传递给它们的子节点,这就是它们到达时看起来像广播的原因,但是当你将自己的UINavigationController子类插入VC层次结构时,你必须自己将这些调用传递给任何子节点UINavigationControllers。如果你想编写自己的“全局控制器VC”,就像UITabBarController的替换一样,你必须这样做。

答案 1 :(得分: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");
        }