Iphone UINavigationController和自动旋转

Iphone UINavigationController和自动旋转,iphone,cocoa-touch,uinavigationcontroller,rotation,Iphone,Cocoa Touch,Uinavigationcontroller,Rotation,我有一个UIViewController,它在shouldAutorotateToInterfaceOrientation:中为UIDeviceOrientationGrait返回YES,为其他所有内容返回NO。在堆栈顶部的视图中,我使用pushViewController:animated:来推送一个新的UIViewController。对于shouldAutorotateToInterfaceOrientation:中的任何内容,新控制器都会返回YES 第一个视图拒绝旋转(如预期的那样)。推

我有一个UIViewController,它在
shouldAutorotateToInterfaceOrientation:
中为
UIDeviceOrientationGrait
返回
YES
,为其他所有内容返回
NO
。在堆栈顶部的视图中,我使用
pushViewController:animated:
来推送一个新的
UIViewController
。对于
shouldAutorotateToInterfaceOrientation:
中的任何内容,新控制器都会返回
YES

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

如果用户将设备旋转回纵向,视图将旋转,然后像以前一样卡在纵向模式中。这是可行的,但在用户旋转回来之前,这对用户来说是丑陋的。所以我在寻找一种方法,使这个视图保持在纵向模式

到目前为止,我找到的唯一解决方法是使用
-[UIDevice setOrientation:
,它会抛出一个警告(
orientation
是只读的),但由于它是实际定义的,所以可以工作。这是一个巨大的黑客,我想要一个真正的解决方案。为了寻找真正的解决方案,我将GDB连接到照片应用程序(MobileSlideshow.app)上,发现它也使用
-[UIDevice setOrientation:][/code>。作为一个内部应用程序,虽然我想他们有不同的规则


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

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

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

  • 将虚拟导航栏配置为与传出的导航控制器完全匹配,并将其直接放置在导航控制器栏的顶部。(您可以复制当前视图控制器的
    UINavigationItem
    的配置并将其推上)
  • 将新的导航控制器置于屏幕右侧边缘
  • 设置新控制器和旧控制器帧从右向左移动的动画
  • 为传入视图控制器创建
    UINavigationItem
    的副本,并将其推到虚拟导航栏上
  • 动画完成后,从视图中删除虚拟
    UINavigationBar
    ,以及传出的导航控制器
  • 所有这些都是大量的工作,但如果你非常聪明(并且非常顽强),你也许能够让它发挥作用。我很想看到结果


    也就是说,您最好只使用
    setOrientation:
    ,并在应用商店审批流程中冒险;-)

    在3.0操作系统上再试一次(现在我们可以讨论它了)。在3.0下,已经解决了这方面的两个特殊情况:

  • 在横向视图上呈现纵向模式视图,反之亦然。邮件中查看附件的3.0之前的行为就是一个例子。您可以旋转到横向以获取PDF,并在取消附件视图时返回邮件的纵向视图。(现在我们在3.0中有了横向消息视图,这种行为似乎已经消失了)

  • 在视图堆栈中混合方向,并在弹出堆栈时获得正确的方向。例如,YouTube应用程序中的电影表视图和电影视图之间的转换


  • 似乎存在一些棘手的美学问题,即所有排列的默认过渡应该是什么样子。如果您在slo mo中查看,会发现一些奇怪的元素,但这比在您自己的代码中向后弯曲要好得多。

    因此,从iOS 1到iOS 4,这一恼人的错误有很长的路要走


    我相信最好的解决方案是复制它,让苹果知道我们真的想要修复它。我刚刚在错误ID 8478525下再次报告了它。

    这是一篇旧文章,但由于它没有被解决。我想分享我的解决方案,为任何其他人谁可能是头痛

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

    问题: 直观地说,我通过检查topViewController是否为rotableViewController来设置选择性的shouldAutorotateToInterfaceOrientation。但是,在以横向模式从rotableViewController弹出后,navigationcontroller现在以横向模式显示,尽管这是不允许的

    解决方案:杀手是禁止在
    视图出现时旋转,并在没有动画的情况下显示和关闭modalViewController

  • appViewController作为主机添加到窗口中 viewController,即比RootViewController更根
  • navigationController添加到appViewController中,带有 委托设置为appViewController
  • 在AppViewController中




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

    UIWindow* window = UIApplication.sharedApplication.keyWindow;
    UIView* view = [window.subviews objectAtIndex:0];
    [view removeFromSuperview];
    [window addSubview:view];
    
    这是给
    - (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated
    {
        [viewController viewDidAppear:animated];
        canRotate = ([navigationController.topViewController isKindOfClass:[MyRotatable class]]);
    }
    
    - (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];
        }
    }
    
    UIWindow* window = UIApplication.sharedApplication.keyWindow;
    UIView* view = [window.subviews objectAtIndex:0];
    [view removeFromSuperview];
    [window addSubview:view];
    
    - (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);
    }
    
    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
    {
        return (interfaceOrientation == UIInterfaceOrientationLandscapeRight) ||
               (interfaceOrientation == UIInterfaceOrientationPortrait);
    }
    
    //auxiliary function
    -(void) fixOrientation:(UIInterfaceOrientation)orientation
    {
        if (orientation == UIInterfaceOrientationPortrait)
            self.view.transform = CGAffineTransformMakeRotation(M_PI_2);
        else if (orientation == UIInterfaceOrientationLandscapeRight)
            self.view.transform = CGAffineTransformMakeRotation(0);
    }
    
    -(void) viewWillAppear:(BOOL)animated
    {
        [self fixOrientation:[[UIApplication sharedApplication] statusBarOrientation]];
    }
    
    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
    {
        [self fixOrientation:interfaceOrientation];
        //notice, that both orientations are accepted
        return (interfaceOrientation == UIInterfaceOrientationLandscapeRight) ||
               (interfaceOrientation == UIInterfaceOrientationPortrait);
    }
    
    //these two functions helps to avoid blinking
    - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
    {
        [UIView setAnimationsEnabled:NO]; // disable animations temporarily
    
    }
    
    - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
    {
        [UIView setAnimationsEnabled:YES]; // rotation finished, re-enable them
    }