我有一个应用程序,我希望在某些视图中支持设备旋转,但其他在横向模式下没有特别的意义,因此当我交换视图时,我想强制将旋转设置为纵向。
UIDevice上有一个未记录的属性设置器可以完成这个技巧,但显然会生成一个编译器警告,并且可能会随着SDK的未来版本而消失。
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortrait];
是否有任何记录方法强制定位?
更新:我想我会提供一个例子,因为我不是在寻找shouldAutorotateToInterfaceOrientation,因为我已经实现了它。
我希望我的应用程序支持View 1中的横向和纵向,但只支持View 2中的纵向。我已经为所有视图实现了shouldAutorotateToInterfaceOrientation但是如果用户在View 1中处于横向模式,然后切换到View 2,我想要强制手机旋转回人像。
答案 0 :(得分:101)
事实上很久以后,但是万一有人不使用导航控制器和/或不想使用未记录的方法:
UIViewController *c = [[UIViewController alloc]init];
[self presentModalViewController:c animated:NO];
[self dismissModalViewControllerAnimated:NO];
[c release];
提供和解雇香草视图控制器就足够了。
显然,您仍然需要确认或拒绝覆盖shouldAutorotateToInterfaceOrientation的方向。但这会导致shouldAutorotate ......被系统再次调用。
答案 1 :(得分:16)
据我所知,setOrientation:
方法不起作用(或者可能不再起作用)。以下是我正在做的事情:
首先,将此定义放在文件的顶部,在#imports:
下#define degreesToRadian(x) (M_PI * (x) / 180.0)
然后,在viewWillAppear:
方法
[[UIApplication sharedApplication] setStatusBarHidden:YES animated:NO];
if (self.interfaceOrientation == UIInterfaceOrientationPortrait) {
self.view.transform = CGAffineTransformIdentity;
self.view.transform = CGAffineTransformMakeRotation(degreesToRadian(90));
self.view.bounds = CGRectMake(0.0, 0.0, 480, 320);
}
如果你想要动画,那么你可以将整个事物包装在一个动画块中,如下所示:
[UIView beginAnimations:@"View Flip" context:nil];
[UIView setAnimationDuration:1.25];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[[UIApplication sharedApplication] setStatusBarHidden:YES animated:NO];
if (self.interfaceOrientation == UIInterfaceOrientationPortrait) {
self.view.transform = CGAffineTransformIdentity;
self.view.transform = CGAffineTransformMakeRotation(degreesToRadian(90));
self.view.bounds = CGRectMake(0.0, 0.0, 480, 320);
}
[UIView commitAnimations];
然后,在您的肖像模式控制器中,您可以执行相反操作 - 检查其当前是否处于横向状态,如果是,则将其旋转回纵向。
答案 2 :(得分:16)
如果你想强制它从纵向旋转到横向,这里是代码。请注意,您需要调整视图的中心。我注意到我没有将视图放在正确的位置。否则,它完美地运作。谢谢你的提示。
if(UIInterfaceOrientationIsLandscape(self.interfaceOrientation)){
[UIView beginAnimations:@"View Flip" context:nil];
[UIView setAnimationDuration:0.5f];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
self.view.transform = CGAffineTransformIdentity;
self.view.transform = CGAffineTransformMakeRotation(degreesToRadian(90));
self.view.bounds = CGRectMake(0.0f, 0.0f, 480.0f, 320.0f);
self.view.center = CGPointMake(160.0f, 240.0f);
[UIView commitAnimations];
}
答案 3 :(得分:7)
有一种简单的方法可以通过编程方式强制iPhone达到必要的方向 - 使用 kdbdallas 已经提供的两个答案, Josh :
//will rotate status bar
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight];
//will re-rotate view according to statusbar
UIViewController *c = [[UIViewController alloc]init];
[self presentModalViewController:c animated:NO];
[self dismissModalViewControllerAnimated:NO];
[c release];
就像一个魅力:)
编辑:
对于iOS 6我需要添加此功能: (适用于模态viewcontroller)
- (NSUInteger)supportedInterfaceOrientations
{
return (UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight);
}
答案 4 :(得分:7)
我遇到了一个问题,我在屏幕上以UIViewController
横向显示了UINavigationController
。但是,当在流程中按下下一个视图控制器时,我需要设备返回纵向。
我注意到的是,当一个新的视图控制器被压入堆栈时,shouldAutorotateToInterfaceOrientation:
方法没有被调用,但是当从堆栈中弹出一个视图控制器时,它被调用 >
利用这一点,我在我的一个应用程序中使用了这段代码:
- (void)selectHostingAtIndex:(int)hostingIndex {
self.transitioning = YES;
UIViewController *garbageController = [[[UIViewController alloc] init] autorelease];
[self.navigationController pushViewController:garbageController animated:NO];
[self.navigationController popViewControllerAnimated:NO];
BBHostingController *hostingController = [[BBHostingController alloc] init];
hostingController.hosting = [self.hostings objectAtIndex:hostingIndex];
[self.navigationController pushViewController:hostingController animated:YES];
[hostingController release];
self.transitioning = NO;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
if (self.transitioning)
return (toInterfaceOrientation == UIInterfaceOrientationPortrait);
else
return YES;
}
基本上,通过创建一个空视图控制器,将其推入堆栈,并立即将其弹出,可以使界面恢复到纵向位置。一旦控制器弹出,我只需按下我打算首先推动的控制器。在视觉上,它看起来很棒 - 用户从未看到空的任意视图控制器。
答案 5 :(得分:7)
我一直在挖掘和挖掘寻找一个很好的解决方案。找到了这篇诀窍的博客文章:从密钥UIWindow
中删除最外层视图并再次添加,系统将重新查询视图控制器中的shouldAutorotateToInterfaceOrientation:
方法,强制执行正确的方向应用。
看到它:iphone forcing uiview to reorientate
答案 6 :(得分:6)
这在后来的iPhone 3.1.2 SDK上不再是问题。现在,它似乎遵守被推回到堆栈的视图的请求方向。这可能意味着您需要检测较旧的iPhone OS版本,并且仅在最新版本之前应用setOrientation。
目前尚不清楚Apple的静态分析是否会理解您正在解决较旧的SDK限制。我个人已经告诉我在下一次更新时删除方法调用,所以我还不确定是否对旧设备进行了黑客攻击会获得审批流程。
答案 7 :(得分:5)
Josh的回答对我来说很好。
但是,我更喜欢发布“方向更改,请更新UI”通知。当视图控制器收到此通知时,它会调用shouldAutorotateToInterfaceOrientation:
,允许您通过返回YES
所需的方向来设置任何方向。
[[NSNotificationCenter defaultCenter] postNotificationName:UIDeviceOrientationDidChangeNotification object:nil];
唯一的问题是这会强制重新定位而不用动画。您需要在beginAnimations:
和commitAnimations
之间包含此行以实现平滑过渡。
希望有所帮助。
答案 8 :(得分:3)
FWIW,这是我手动设置方向的实现(进入应用程序的根视图控制器,natch):
-(void)rotateInterfaceToOrientation:(UIDeviceOrientation)orientation{
CGRect bounds = [[ UIScreen mainScreen ] bounds ];
CGAffineTransform t;
CGFloat r = 0;
switch ( orientation ) {
case UIDeviceOrientationLandscapeRight:
r = -(M_PI / 2);
break;
case UIDeviceOrientationLandscapeLeft:
r = M_PI / 2;
break;
}
if( r != 0 ){
CGSize sz = bounds.size;
bounds.size.width = sz.height;
bounds.size.height = sz.width;
}
t = CGAffineTransformMakeRotation( r );
UIApplication *application = [ UIApplication sharedApplication ];
[ UIView beginAnimations:@"InterfaceOrientation" context: nil ];
[ UIView setAnimationDuration: [ application statusBarOrientationAnimationDuration ] ];
self.view.transform = t;
self.view.bounds = bounds;
[ UIView commitAnimations ];
[ application setStatusBarOrientation: orientation animated: YES ];
}
结合以下UINavigationControllerDelegate
方法(假设您使用的是UINavigationController
):
-(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
// rotate interface, if we need to
UIDeviceOrientation orientation = [[ UIDevice currentDevice ] orientation ];
BOOL bViewControllerDoesSupportCurrentOrientation = [ viewController shouldAutorotateToInterfaceOrientation: orientation ];
if( !bViewControllerDoesSupportCurrentOrientation ){
[ self rotateInterfaceToOrientation: UIDeviceOrientationPortrait ];
}
}
根据传入的UIViewController
是否支持当前设备方向,负责旋转根视图。最后,您需要将rotateInterfaceToOrientation
与实际的设备方向更改联系起来,以模仿标准的iOS功能。将此事件处理程序添加到同一根视图控制器:
-(void)onUIDeviceOrientationDidChangeNotification:(NSNotification*)notification{
UIViewController *tvc = self.rootNavigationController.topViewController;
UIDeviceOrientation orientation = [[ UIDevice currentDevice ] orientation ];
// only switch if we need to (seem to get multiple notifications on device)
if( orientation != [[ UIApplication sharedApplication ] statusBarOrientation ] ){
if( [ tvc shouldAutorotateToInterfaceOrientation: orientation ] ){
[ self rotateInterfaceToOrientation: orientation ];
}
}
}
最后,在UIDeviceOrientationDidChangeNotification
或init
注册loadview
通知,如下所示:
[[ NSNotificationCenter defaultCenter ] addObserver: self
selector: @selector(onUIDeviceOrientationDidChangeNotification:)
name: UIDeviceOrientationDidChangeNotification
object: nil ];
[[ UIDevice currentDevice ] beginGeneratingDeviceOrientationNotifications ];
答案 9 :(得分:2)
这对我有用(谢谢Henry Cooke):
我的目标只是处理景观方向的变化。
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(orientationChanged:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
- (void)orientationChanged:(NSNotification *)notification {
//[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
UIDeviceOrientation orientation = [UIDevice currentDevice].orientation;
CGRect bounds = [[ UIScreen mainScreen ] bounds ];
CGAffineTransform t;
CGFloat r = 0;
switch ( orientation ) {
case UIDeviceOrientationLandscapeRight:
r = 0;
NSLog(@"Right");
break;
case UIDeviceOrientationLandscapeLeft:
r = M_PI;
NSLog(@"Left");
break;
default:return;
}
t = CGAffineTransformMakeRotation( r );
UIApplication *application = [ UIApplication sharedApplication ];
[ UIView beginAnimations:@"InterfaceOrientation" context: nil ];
[ UIView setAnimationDuration: [ application statusBarOrientationAnimationDuration ] ];
self.view.transform = t;
self.view.bounds = bounds;
[ UIView commitAnimations ];
[ application setStatusBarOrientation: orientation animated: YES ];
}
答案 10 :(得分:1)
iOS 6解决方案:
[[[self window] rootViewController] presentViewController:[[UIViewController alloc] init] animated:NO completion:^{
[[[self window] rootViewController] dismissViewControllerAnimated:NO completion:nil];
}];
确切的代码取决于每个应用程序以及放置它的位置(我在AppDelegate中使用它)。将[[self window] rootViewController]
替换为您使用的内容。我使用的是UITabBarController
。
答案 11 :(得分:1)
我最终很容易解决这个问题。我尝试了上面的所有建议,但仍然很简短,所以这是我的解决方案:
在需要保持横向(左或右)的ViewController中,我会听取方向更改:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(didRotate:)
name:UIDeviceOrientationDidChangeNotification object:nil];
然后在didRotate中:
- (void) didRotate:(NSNotification *)notification
{ if (orientationa == UIDeviceOrientationPortrait)
{
if (hasRotated == NO)
{
NSLog(@"Rotating to portait");
hasRotated = YES;
[UIView beginAnimations: @"" context:nil];
[UIView setAnimationDuration: 0];
self.view.transform = CGAffineTransformIdentity;
self.view.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(-90));
self.view.bounds = CGRectMake(0.0f, 0.0f, 480.0f, 320.0f);
self.view.frame = CGRectMake(0.0f, 0.0f, 480.0f, 320.0f);
[UIView commitAnimations];
}
}
else if (UIDeviceOrientationIsLandscape( orientationa))
{
if (hasRotated)
{
NSLog(@"Rotating to lands");
hasRotated = NO;
[UIView beginAnimations: @"" context:nil];
[UIView setAnimationDuration: 0];
self.view.transform = CGAffineTransformIdentity;
self.view.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(0));
self.view.bounds = CGRectMake(0.0f, 0.0f, 320.0f, 480.0f);
self.view.frame = CGRectMake(0.0f, 0.0f, 320.0f, 480.0f);
[UIView commitAnimations];
}
}
请记住任何使用自动调整大小的超级视图/子视图,因为view.bounds / frame正在显式重置...
保持视图Landscape的这种方法的唯一警告是,必须发生的方向之间的固有动画切换,最好是让它看起来没有变化。
答案 12 :(得分:1)
我有一个应用程序,我希望在某些视图中支持设备旋转,但其他在横向模式下没有特别的意义,因此当我交换视图时,我想强制将旋转设置为纵向。
我意识到这个帖子中的上述原帖现在已经很老了,但我遇到了类似的问题 - 即。我的应用程序中的所有屏幕都只是纵向,除了一个屏幕,用户可以在横向和纵向之间旋转。
这很简单,但与其他帖子一样,我希望应用程序在返回上一个屏幕时自动返回纵向,而不管当前的设备方向。
我实施的解决方案是在横向模式下隐藏导航栏,这意味着用户只能在纵向时返回到先前的屏幕。因此,所有其他屏幕只能是纵向的。
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)pInterfaceOrientation {
BOOL lHideNavBar = self.interfaceOrientation == UIInterfaceOrientationPortrait ? NO : YES;
[self.navigationController setNavigationBarHidden:lHideNavBar animated:YES];
}
这也为我的应用程序带来了额外的好处,因为在横向模式下有更多的屏幕空间可用。这很有用,因为有问题的屏幕用于显示PDF文件。
希望这有帮助。
答案 13 :(得分:0)
我找到了一个解决方案并用法语写了一些东西(但代码是英文的)。 here
方法是将控制器添加到窗口视图中(控制器必须具有shouldRotate ....函数的良好实现)。
答案 14 :(得分:-3)
这就是我使用的。 (你得到一些编译警告,但它在模拟器和iPhone中都有效)
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight];
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight];
答案 15 :(得分:-3)
我认为这不可能在运行时进行,但您当然可以对您的UI应用90度变换。
答案 16 :(得分:-3)
如果您使用的是UIViewControllers,则有以下方法:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
为包含您不想旋转的视图的视图控制器返回NO
。