【问题标题】:iPhone - Working with Orientation and Multiple ViewsiPhone - 使用方向和多个视图
【发布时间】:2011-03-11 07:27:04
【问题描述】:

为了弄清楚这一点,我进行了漫长而艰苦的搜索。我花了大约 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; 
    }

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

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

当 IPHONE 改变方向时它不会旋转。这是因为它的超级视图说它不想旋转。一旦超级视图返回 no,子视图甚至不会被询问。所以相反,我们游戏视图控制器只是说不,我不想自动旋转到任何视图。然后我们注册一个方向改变的通知,并调用我们自己的旋转方法。

最后这些代码是您自己处理旋转的方式。从 didRotate 内部调用 rotateView。请注意,我只希望用户在选择难度后能够旋转,所以我的 didRotate 方法中有逻辑来确定它是否应该旋转。代码中的 cmets 会解释为什么会发生某些事情。

-(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;
    }
}

我希望这对某人有所帮助,我知道我在使用它时非常艰难,尤其是键盘从横向变为纵向。

【问题讨论】:

  • 此评论与方向无关,但我正在查看您的应用程序,就像您用于短语“让我们这样做!”的字体一样那是什么字体?
  • 字体被称为“Blade 2”(我猜是受电影启发)。

标签: iphone ipad ipod-touch


【解决方案1】:

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

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

【讨论】:

  • “每个屏幕一个 UIViewController”实际上从未在任何内容中提及。您所说的是“每个视图一个视图控制器”,它表示视图控制器和它们控制的视图之间具有一对一的关系是一个好主意,这只是程序员使用的常见约定。除此之外,它不是“规则”,而是用于使事情“更容易”的指南。此外,视图控制器会自动将消息传递给其子视图控制器。如果将所有 shouldAutorotateToInterfaceOrientation 方法设置为返回 YES,它们都会旋转
  • 您是说 .../customVC-A/customVC-B 的层次结构中,customVC-B 将自动调用其定向方法,而不必在 VC-A 中显式转发它们?这不是我所看到的,但话说回来,我并没有那么多嵌套自定义 VC。
  • nope,就是说VC-A/VC-B会先调用VC-A的定向方法,如果返回no则不调用VC-B的方法。
  • @ColdLogic: developer.apple.com/library/ios/#featuredarticles/… "您不应使用多个自定义视图控制器来管理同一视图层次结构的不同部分。"
  • @user102008:我不...有 3 个不同的视图由不同的视图控制器管理。 “您不应使用多个自定义视图控制器来管理同一视图层次结构的不同部分。同样,您不应使用单个自定义视图控制器对象来管理多个屏幕的内容。”
【解决方案2】:
 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");
        }

【讨论】:

  • 为提高您的帖子质量,请说明您的答案为何/如何解决问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-19
  • 1970-01-01
  • 2011-03-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多