objective-c 是否有记录的方法来设置 iPhone 方向?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/181780/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is there a documented way to set the iPhone orientation?
提问by Dave Verwer
I have an app where I would like to support device rotation in certain views but other don't particularly make sense in Landscape mode, so as I swapping the views out I would like to force the rotation to be set to portrait.
我有一个应用程序,我想在某些视图中支持设备旋转,但其他视图在横向模式下没有特别意义,因此当我交换视图时,我想强制将旋转设置为纵向。
There is an undocumented property setter on UIDevice that does the trick but obviously generates a compiler warning and could disappear with a future revision of the SDK.
UIDevice 上有一个未记录的属性设置器可以完成此操作,但显然会生成编译器警告,并且可能会随着 SDK 的未来版本而消失。
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortrait];
Are there any documented ways to force the orientation?
是否有任何记录的方法来强制定向?
Update:I thought I would provide an example as I am not looking for shouldAutorotateToInterfaceOrientation as I have already implemented that.
更新:我想我会提供一个例子,因为我不是在寻找 shouldAutorotateToInterfaceOrientation,因为我已经实现了它。
I want my app to support landscape and portrait in View 1 but only portrait in View 2. I have already implemented shouldAutorotateToInterfaceOrientation for all views but if the user is in landscape mode in View 1 and then switches to View 2, I want to force the phone to rotate back to Portrait.
我希望我的应用程序在视图 1 中支持横向和纵向,但在视图 2 中仅支持纵向。我已经为所有视图实现了 shouldAutorotateToInterfaceOrientation 但如果用户在视图 1 中处于横向模式然后切换到视图 2,我想强制手机旋转回纵向。
采纳答案by John K
This is no longer an issue on the later iPhone 3.1.2 SDK. It now appears to honor the requested orientation of the view being pushed back onto the stack. That likely means that you would need to detect older iPhone OS versions and only apply the setOrientation when it is prior to the latest release.
这在以后的 iPhone 3.1.2 SDK 上不再是问题。它现在似乎尊重被推回堆栈的视图的请求方向。这可能意味着您需要检测较旧的 iPhone 操作系统版本,并且仅在最新版本之前应用 setOrientation。
It is not clear if Apple's static analysis will understand that you are working around the older SDK limitations. I personally have been told by Apple to remove the method call on my next update so I am not yet sure if having a hack for older devices will get through the approval process.
目前尚不清楚 Apple 的静态分析是否会理解您正在解决旧的 SDK 限制。我个人已经被 Apple 告知在我的下一次更新中删除方法调用,所以我不确定是否可以通过批准程序对旧设备进行黑客攻击。
回答by Josh
This is long after the fact, but just in case anybody comes along who isn't using a navigation controller and/or doesn't wish to use undocumented methods:
这是事后很久,但以防万一有人不使用导航控制器和/或不希望使用未记录的方法:
UIViewController *c = [[UIViewController alloc]init];
[self presentModalViewController:c animated:NO];
[self dismissModalViewControllerAnimated:NO];
[c release];
It is sufficient to present and dismiss a vanilla view controller.
呈现和关闭普通视图控制器就足够了。
Obviously you'll still need to confirm or deny the orientation in your override of shouldAutorotateToInterfaceOrientation. But this will cause shouldAutorotate... to be called again by the system.
显然,您仍然需要在覆盖 shouldAutorotateToInterfaceOrientation 时确认或拒绝方向。但这会导致 shouldAutorotate... 被系统再次调用。
回答by Bdebeez
From what I can tell, the setOrientation:method doesn't work (or perhaps works no longer). Here's what I'm doing to do this:
据我所知,该setOrientation:方法不起作用(或者可能不再起作用)。这是我正在做的事情:
first, put this define at the top of your file, right under your #imports:
首先,将此定义放在文件顶部,就在 #imports 下方:
#define degreesToRadian(x) (M_PI * (x) / 180.0)
then, in the viewWillAppear:method
然后,在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);
}
if you want that to be animated, then you can wrap the whole thing in an animation block, like so:
如果您希望将其设置为动画,则可以将整个内容包装在一个动画块中,如下所示:
[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];
Then, in your portrait mode controller, you can do the reverse - check to see if its currently in landscape, and if so, rotate it back to Portrait.
然后,在您的纵向模式控制器中,您可以执行相反的操作 - 检查它当前是否处于横向,如果是,则将其旋转回纵向。
回答by Michael Gaylord
If you want to force it to rotate from portrait to landscape here is the code. Just note that you need adjust the center of your view. I noticed that mine didn't place the view in the right place. Otherwise, it worked perfectly. Thanks for the tip.
如果你想强制它从纵向旋转到横向,这里是代码。请注意,您需要调整视图的中心。我注意到我的视图没有放在正确的位置。否则,它完美地工作。谢谢你的提示。
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];
}
回答by Andrew Vilcsak
I was having an issue where I had a UIViewControlleron the screen, in a UINavigationController, in landscape orientation. When the next view controller is pushed in the flow, however, I needed the device to return to portrait orientation.
我遇到了一个问题,我UIViewController在屏幕上有一个,在一个UINavigationController,横向。然而,当下一个视图控制器被推送到流程中时,我需要设备返回到纵向。
What I noticed, was that the shouldAutorotateToInterfaceOrientation:method isn't called when a new view controller is pushed onto the stack, but it is called when a view controller is popped from the stack.
我注意到的是,shouldAutorotateToInterfaceOrientation:当一个新的视图控制器被推入堆栈时,该方法不会被调用,而是在一个视图控制器从堆栈中弹出时被调用。
Taking advantage of this, I am using this snippet of code in one of my apps:
利用这一点,我在我的一个应用程序中使用了这段代码:
- (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;
}
Basically, by creating an empty view controller, pushing it onto the stack, and immediately popping it off, it's possible to get the interface to revert to the portrait position. Once the controller has been popped, I just push on the controller that I intended to push in the first place. Visually, it looks great - the empty, arbitrary view controller is never seen by the user.
基本上,通过创建一个空的视图控制器,将其推入堆栈,然后立即将其弹出,可以让界面恢复到纵向位置。弹出控制器后,我只需按下我打算首先按下的控制器。从视觉上看,它看起来很棒 - 用户永远不会看到空的、任意的视图控制器。
回答by Rafael Nobre
I've been digging and digging looking for a good solution to this. Found this blog post that does the trick: remove your outermost view from the key UIWindowand add it again, the system will then re-query the shouldAutorotateToInterfaceOrientation:methods from your viewcontrollers, enforcing the correct orientation to be applied.
See it : iphone forcing uiview to reorientate
我一直在挖掘和挖掘寻找一个好的解决方案。发现这篇博文可以解决问题:从键中删除最外面的视图UIWindow并再次添加它,然后系统将从您的视图shouldAutorotateToInterfaceOrientation:控制器中重新查询方法,强制应用正确的方向。看看吧:iphone 强制 uiview 重新定位
回答by Guntis Treulands
There is a simple way to programmatically force iPhone to the necessary orientation - using two of already provided answers by kdbdallas, Josh:
有一种简单的方法可以以编程方式强制 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];
works like a charm :)
奇迹般有效 :)
EDIT:
编辑:
for iOS 6 I need to add this function: (works on modal viewcontroller)
对于 iOS 6,我需要添加此功能:(适用于模态视图控制器)
- (NSUInteger)supportedInterfaceOrientations
{
return (UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight);
}
回答by Christian Schnorr
Josh's answer works fine for me.
乔希的回答对我来说很好。
However, I prefer posting an "orientation did change, please update UI"notification. When this notification is received by a view controller, it calls shouldAutorotateToInterfaceOrientation:, allowing you to set any orientation by returning YESfor the orientation you want.
但是,我更喜欢发布“方向确实改变了,请更新 UI”通知。当视图控制器收到此通知时,它会调用shouldAutorotateToInterfaceOrientation:,允许您通过返回YES所需的方向来设置任何方向。
[[NSNotificationCenter defaultCenter] postNotificationName:UIDeviceOrientationDidChangeNotification object:nil];
The only problem is that this forces a re-orientation withoutan animation. You would need to wrap this line between beginAnimations:and commitAnimationsto achieve a smooth transition.
唯一的问题是这会在没有动画的情况下强制重新定向。您需要将这条线包裹在beginAnimations:和之间commitAnimations以实现平滑过渡。
Hope that helps.
希望有帮助。
回答by Henry Cooke
FWIW, here's my implementation of manually setting orientation (to go in your app's root view controller, natch):
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 ];
}
coupled with the following UINavigationControllerDelegatemethod (assuming you're using a UINavigationController):
再加上以下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 ];
}
}
That takes care of rotating the root view according to whether an incoming UIViewControllersupports the current device orientation. Finally, you'll want to hook up rotateInterfaceToOrientationto actual device orientation changes in order to mimic standard iOS functionality. Add this event handler to the same root view controller:
这负责根据传入是否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 ];
}
}
}
Finally, register for UIDeviceOrientationDidChangeNotificationnotifications in initor loadviewlike so:
最后,UIDeviceOrientationDidChangeNotification在init或loadview像这样注册通知:
[[ NSNotificationCenter defaultCenter ] addObserver: self
selector: @selector(onUIDeviceOrientationDidChangeNotification:)
name: UIDeviceOrientationDidChangeNotification
object: nil ];
[[ UIDevice currentDevice ] beginGeneratingDeviceOrientationNotifications ];
回答by user324168
This works for me (thank you Henry Cooke):
这对我有用(谢谢亨利库克):
The aim for me was to deal with landscape orientations changes only.
我的目标是仅处理横向变化。
init method:
初始化方法:
[[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 ];
}

