UINavigationController和autorotation
我有一个UIViewController,在shouldAutorotateToInterfaceOrientation:
中为UIDeviceOrientationPortrait
和NO
返回YES
。在堆栈顶部显示该视图时,我使用pushViewController:animated:
推送新的UIViewController
。对于shouldAutorotateToInterfaceOrientation:
中的任何内容,新控制器将返回YES
。UINavigationController和autorotation
第一个视图拒绝旋转(如预期的那样)。一旦推入第二个视图,用户可以旋转设备,UI将旋转(也如预期的那样)。如果第二个视图处于横向模式,并且用户按下后退按钮(调用popViewControllerAnimated:
),则第一个视图将出现旋转(意外!)。
如果用户将设备旋转回纵向,视图将旋转,然后像以前一样卡入纵向模式。这可以工作,但用户直到他们旋转后才会变丑。所以我正在寻找一种方法让这个视图保持纵向模式。
迄今为止我发现的唯一解决方法是使用-[UIDevice setOrientation:]
,它会引发警告(orientation
是只读的),但由于它是实际定义的,所以会起作用。这是一个巨大的黑客攻击,我想要一个真正的解决方案。为了寻找真正的解决方案,我将GDB附加到Photos应用程序(MobileSlideshow.app)中,并发现它也使用-[UIDevice setOrientation:]
。虽然我猜他们有不同的规则,但作为内部应用程序。
是否有正确的方法来实现预期的自转行为?
我正要告诉你,可能没有办法,但后来我有了一个想法。如果你使用两个单独的UINavigationController
s:一个控制根视图并禁止旋转,一个用于允许它的子视图,你可能能够使它工作。您将手动处理往来根控制器和子控制器的转换。
你必须修补儿童导航控制器以拥有正确的后退按钮。当然,你必须处理后退按钮。您可能必须使用虚拟UINavigationBar
才能从一个导航控制器执行动画,以便转换看起来正确。您还必须为导航控制器之间的“推送”过渡设置动画,这可能需要稍微调整以使其看起来正确。您将不得不:
- 配置一个虚拟导航栏,使其与导航控制器完全匹配,并将其直接放置在导航控制器栏的顶部。在右边缘
- (您可以复制当前视图控制器的
UINavigationItem
的配置,并推动它) - 将新的导航控制器关闭屏幕从右到左的动画新老控制器的帧的运动
- 用于输入视图控制器创建
UINavigationItem
的副本,并推动它虚设导航栏 - 当在动画完成上,从视图中去除伪
UINavigationBar
,并且还传出导航控制器。
所有这些都是很多工作,但是如果你非常聪明(而且非常坚韧),那么你可能会得到它的工作。我很想看到结果!
这就是说,你可能会更好只使用setOrientation:
,并采取与App Store的审批流程;-)
与3.0 OS再试一次(现在我们可以谈论它),你的机会。这两种特殊情况已经在3.0摸索出:
呈现肖像模式的看法在横向视图,反之亦然。一个例子是邮件中用于查看附件的3.0版之前的行为。您可以旋转以横向查看PDF并在取消附件视图时恢复消息的纵向视图。 (现在我们在3.0中已经有了横向消息视图,这种行为似乎已经消失了)。
混合视图堆栈中的方向并在弹出堆栈时返回正确的方向。一个例子是电影的桌面视图和YouTube应用中的电影视图之间的转换。
似乎有一些棘手的审美问题,如何默认过渡所有的排列应该看起来。如果你用慢镜头查看,有一些奇怪的元素,但它会在你自己的代码中向后弯曲。
我试过这个,#1似乎工作正常,但#2不适合我。我使用表格视图控制器设置了一个导航控制器项目。根视图不能旋转,但推送的视图可以。当你弹出第二个视图时,它将保持旋转状态。实际上,导航栏项目似乎很困惑,甚至在弹出它后显示第二个视图的标题。 – 2010-02-01 04:36:32
所以这个恼人的错误是一个很难很长的路要走,从iOS的1到iOS 4
我相信我们有它复制this bug,让苹果知道我们真的希望它固定的最佳解决方案。我刚刚在bug ID 8478525下再次报告了它。
这是一篇旧帖子,但是因为它尚未解决。我想分享我的解决方案,对于任何其他可能头痛的人。
目标: UINavigationController和堆栈中的大多数viewcontrollers固定在纵向,除了堆栈中的一个viewcontroller被允许旋转到纵向和横向。
问题: 直观地,我通过检查topViewController是否为rotableViewController来设置选择性的shouldAutorotateToInterfaceOrientation。但是,在风景模式下从rotableViewController回弹后,导航控制器现在以横向模式显示,尽管不允许。
解决方案:杀手将禁止旋转viewWillAppear
,并且当前&关闭一个没有动画的modalViewController。
- appViewController作为主机 viewController添加到窗口中,即,Rooter比RootViewController;
- 将navigationController添加到appViewController,并将 委托设置为appViewController;
- 在AppViewController
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (interfaceOrientation == UIInterfaceOrientationPortrait) return YES;
return canRotate;
}
- (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];
}
}
到的UIDevice setOrientation的法律替代如下:
UIWindow* window = UIApplication.sharedApplication.keyWindow;
UIView* view = [window.subviews objectAtIndex:0];
[view removeFromSuperview];
[window addSubview:view];
强制当前视图控制器,以评估其方向,调用shouldAutorotateToInterfaceOrientation和任何违禁方向切换了。
E.g.下面的代码将在支持所有方向,但其母公司视图控制器只能用于支持横向:
- (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);
}
我发现这个问题一个很好的解决方法。线索是支持所有方位为所有在UINavigationController
的意见。
我在控制器中有2个视图。根视图仅支持LandscapeRight
,第二种支持支持LandscapeRight
和Portrait
。
第二视图shouldAutorotateToInterfaceOrientation
方法看起来像往常一样:
- (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
}
iOS 5增加了+ [UIViewController attemptRotationToDeviceOrientation],它为我解决了这个问题。
根据文档(“尝试将所有窗口旋转到设备的方向”),似乎这是针对反向用例的,即您推送一个新的视图控制器,支持前一个不支持的界面方向。 – Koraktor 2013-01-04 18:40:47
我相信有应用程序的例子(大概)在应用程序商店中使用setOrientation。一个是Tweetie,它可以在写推文时强制风景键盘。也许他们逃避了它,因为它不是默认设置。 – 2009-06-09 15:50:50
现在是2014年,这个问题仍然发生在ios 8上。有没有人找到真正的答案,但这个问题看起来不像黑客? – 2014-10-31 16:17:59