UINavigationController和autorotation

Ste*_*eld 24 iphone cocoa-touch rotation uinavigationcontroller

我有一个返回一个UIViewController YESshouldAutorotateToInterfaceOrientation:UIDeviceOrientationPortraitNO其他一切.在堆栈顶部的那个视图中,我pushViewController:animated:用来推动一个新的UIViewController.新控制器返回YES任何内容shouldAutorotateToInterfaceOrientation:.

第一个视图拒绝旋转(如预期的那样).按下第二个视图后,用户可以旋转设备,UI将旋转(也如预期).如果第二个视图处于横向模式并且用户按下后退按钮(调用popViewControllerAnimated:),则第一个视图将显示为旋转(意外!).

如果用户将设备旋转回纵向,则视图将旋转,然后像以前一样卡在纵向模式中.这可行,但对于用户来说,它们会旋转回来之前很难看.所以我正在寻找一种让这种观点保持纵向模式的方法.

到目前为止我找到的唯一解决方法是使用-[UIDevice setOrientation:],它会抛出一个警告(orientation只读),但是因为实际定义了它.这是一个巨大的黑客,我想要一个真正的解决方案.为了寻找真正的解决方案,我将GDB附加到了Photos应用程序(MobileSlideshow.app)并发现它也使用了-[UIDevice setOrientation:].作为一个内部应用程序虽然我猜他们有不同的规则.

有没有正确的方法来实现预期的自转行为?

Rob*_*bin 6

UIDevice setOrientation的合法替代方法如下:

UIWindow* window = UIApplication.sharedApplication.keyWindow;
UIView* view = [window.subviews objectAtIndex:0];
[view removeFromSuperview];
[window addSubview:view];
Run Code Online (Sandbox Code Playgroud)

这会强制当前视图控制器评估其方向,调用shouldAutorotateToInterfaceOrientation并切换远离任何禁止的方向.

例如,以下代码将用于支持所有方向但其父级仅支持格局的视图控制器中:

- (void)popBack
{
    [self.navigationController popToRootViewControllerAnimated:YES]; 
}

- (IBAction)backPressed:(id)sender
{   
    portraitOrientationPermitted = NO;

    // Force the framework to re-evaluate the interface orientation.
    UIWindow* window = UIApplication.sharedApplication.keyWindow;
    UIView* view = [window.subviews objectAtIndex:0];
    [view removeFromSuperview];
    [window addSubview:view];

    [self performSelector:@selector(popBack) withObject:nil afterDelay:0.8];

    portraitOrientationPermitted = YES;
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return portraitOrientationPermitted || 
        UIInterfaceOrientationIsLandscape(interfaceOrientation);
}
Run Code Online (Sandbox Code Playgroud)

  • 在iOS 7上没有为我工作.但是,删除窗口的rootViewController并将其重新放入.只是把它放在那里以防有人遇到同样的问题. (2认同)

xin*_*.sg 5

这是一个老帖子,但因为它还没有解决.我想与其他可能头疼的人分享我的解决方案.

目标:UINavigationController和其堆栈中的大多数viewcontrollers固定在纵向,除了堆栈中的一个viewcontroller允许旋转到纵向和横向.

问题:直观地我通过检查topViewController是否是rotableViewController来设置一个选择性的shouldAutorotateToInterfaceOrientation.但是,在横向模式下从rotableViewController弹回后,导航控制器现在以横向模式显示,尽管不允许.

解决方案:杀手是禁止旋转,viewWillAppear并在没有动画的情况下呈现和解除modalViewController.

  1. appViewController作为主机viewController添加到窗口中,即RootViewController的rooter;
  2. navigationController被添加到appViewController,委托设置为appViewController;
  3. 在AppViewController中


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    if (interfaceOrientation == UIInterfaceOrientationPortrait) return YES;
    return canRotate;
}
Run Code Online (Sandbox Code Playgroud)


- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    [viewController viewDidAppear:animated];
    canRotate = ([navigationController.topViewController isKindOfClass:[MyRotatable class]]);
}
Run Code Online (Sandbox Code Playgroud)


- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    [viewController viewWillAppear:animated];
    if (![navigationController.topViewController isKindOfClass:[MyRotatable class]]) {
        canRotate = NO;
        UIViewController * blanck = [[UIViewController alloc] initWithNibName:nil bundle:nil];
        [self presentModalViewController:blanck animated:NO];
        [self dismissModalViewControllerAnimated:NO];
        [blanck release];
    }
}
Run Code Online (Sandbox Code Playgroud)


Ale*_*lex 1

我正想告诉你,可能没有办法,但后来我有了一个想法。很难做到正确,但如果您使用两个单独的UINavigationControllers ,您也许可以使其工作:一个控制根视图并禁止旋转,另一个用于允许旋转的子视图。您将手动处理根控制器和子控制器之间的转换。

您必须修补子导航控制器才能拥有正确的后退按钮。当然,您必须自己按下后退按钮。您可能必须使用虚拟对象UINavigationBar来执行从一个导航控制器到下一个导航控制器的动画,以便过渡看起来正确。您还必须为导航控制器之间的“推送”转换设置动画,这可能需要进行一些调整才能使其看起来正确。你必须:

  1. 配置虚拟导航栏以与传出的导航控制器完全匹配,并将其直接放置在导航控制器栏的顶部。(您可以复制当前视图控制器的配置UINavigationItem并将其推送)
  2. 将新的导航控制器放置在屏幕外的右边缘
  3. 对新旧控制器的帧从右到左的移动进行动画处理
  4. UINavigationItem为传入视图控制器创建一个副本并将其推送到虚拟导航栏上
  5. 动画完成后,UINavigationBar从视图中删除虚拟对象以及传出的导航控制器。

所有这些都需要大量工作,但如果您非常聪明(并且非常顽强),您也许能够让它发挥作用。我很想看到结果!

也就是说,您最好只使用setOrientation:App Store 审批流程并抓住机会;-)