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