如何以编程方式在iOS7中设置设备方向?
我正在使用一个iPad应用程序,使用自动布局,如果用户启用某种模式(“抬头”模式),我只想支持肖像(或肖像倒置)方向,此外,如果设备在风景,我想自动切换到肖像模式。
在顶视图控制器中,我有以下几点:
- (NSUInteger) supportedInterfaceOrientations { if (self.modeHeadsUp) { return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown; } else { return UIInterfaceOrientationMaskAll; } } - (BOOL) shouldAutorotate { return TRUE; }
根据我在别处看到的答案,答案似乎是我应该使用“应用程序setStatusBarOrientation”。 因此,在用户select“抬头”模式的方法中,我包括:
UIApplication *application = [UIApplication sharedApplication]; [application setStatusBarOrientation:UIInterfaceOrientationPortrait animated:YES];
但是,这似乎并没有做任何事情。 虽然我可以物理移动设备,让它旋转成肖像,但它不会自动执行。
实际上,在运行上面的代码之后,在横向模式下尝试以编程方式设置方向时,使用以下代码查询应用程序“statusBarOrientation”时,横向将保持为“4”:
UIApplication *application = [UIApplication sharedApplication]; int orientation = [application statusBarOrientation]; self.movesTextView.text = [NSString stringWithFormat:@"ORIENTATION %d", orientation];
它似乎也许自动布局没有被setStatusBarOrientation触发,所以我试图添加此代码后,没有任何效果:
[super updateViewConstraints]; [self.view updateConstraints];
我意识到苹果希望将设备方向留在用户手中。 但是,我不希望在“抬头”模式下支持横向模式。
我是否错过了能够强制改变方向的东西?
对于iOS 7和8:
Objective-C的:
NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft]; [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
迅速:
let value = UIInterfaceOrientation.LandscapeLeft.rawValue UIDevice.currentDevice().setValue(value, forKey: "orientation")
我在- viewDidAppear:
用这个。 定位问题的完美解决scheme
[[UIDevice currentDevice] setValue: [NSNumber numberWithInteger: UIInterfaceOrientationPortrait] forKey:@"orientation"];
当条件发生变化时,您需要调用attemptRotationToDeviceOrientation (UIViewController)
以使系统调用supportedInterfaceOrientations
。
这适用于Xcode
6&5。
- (BOOL)shouldAutorotate { return YES; } - (NSUInteger)supportedInterfaceOrientations { return (UIInterfaceOrientationMaskPortrait); }
NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft]; [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
确实有效,但是你必须在视图控制器中返回YESAutorotate
- (BOOL)shouldAutorotate { return self.shouldAutoRotate; }
但是,如果你这样做,你的VC将自动旋转,如果用户旋转设备…所以我把它改为:
@property (nonatomic, assign) BOOL shouldAutoRotate; - (BOOL)shouldAutorotate { return self.shouldAutoRotate; }
我打电话
- (void)swithInterfaceOrientation:(UIInterfaceOrientation)orientation { self.rootVC.shouldAutoRotate = YES; NSNumber *value = [NSNumber numberWithInt: orientation]; [[UIDevice currentDevice] setValue:value forKey:@"orientation"]; }
用button单击强制一个新的方向。 要设置回应shouldAutoRotate为NO,我添加到我的rootVC
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { self.shouldAutoRotate = NO; }
PS:这个解决方法也适用于所有模拟器。
对我来说唯一的方法就是展示虚拟模态视图控制器。
UIViewController* dummyVC = [[UIViewController alloc] init]; dummyVC.view = [[UIView alloc] init]; [self presentModalViewController:dummyVC animated:NO]; [self dismissModalViewControllerAnimated:NO];
模态视图控制器closures时,VC将被要求更新界面方向。
好奇的是,UINavigationController在按下/popup具有不同支持的界面方向的子视图控制器(在iOS 6.1,7.0上testing)时完成了这一操作。
如果要将应用程序的主视图locking为纵向,但希望在横向中打开popup视图,并且您正在使用tabBarController作为rootViewController,则可以在AppDelegate上使用此代码。
AppDelegate.h
@interface AppDelegate : UIResponder <UIApplicationDelegate, UITabBarControllerDelegate> @property (strong, nonatomic) UIWindow *window; @property (strong, nonatomic) UITabBarController *tabBarController; @end
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Create a tab bar and set it as root view for the application self.tabBarController = [[UITabBarController alloc] init]; self.tabBarController.delegate = self; self.window.rootViewController = self.tabBarController; ... } - (NSUInteger)tabBarControllerSupportedInterfaceOrientations:(UITabBarController *)tabBarController { return UIInterfaceOrientationMaskPortrait; } - (UIInterfaceOrientation)tabBarControllerPreferredInterfaceOrientationForPresentation:(UITabBarController *)tabBarController { return UIInterfaceOrientationPortrait; }
它工作得很好。
在viewController中,您想要在横向上呈现,您只需使用以下内容:
- (NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskLandscape; } - (BOOL)shouldAutorotate { return YES; }
-
将此语句添加到
AppDelegate.h
//whether to allow cross screen marker @property (nonatomic, assign) allowRotation BOOL;
-
将这部分代码写入
AppDelegate.m
- (UIInterfaceOrientationMask) application: (UIApplication *) supportedInterfaceOrientationsForWindow: application (UIWindow *) window { If (self.allowRotation) { UIInterfaceOrientationMaskAll return; } UIInterfaceOrientationMaskPortrait return; }
-
更改委托应用程序的
allowRotation
属性
这个解决scheme可以让你强制一定的接口方向,暂时覆盖UIDevice.current.orientation
的值,然后让系统旋转接口来匹配设备的旋转:
重要提示:这是一个黑客攻击,可能随时停止工作
在您的应用的根视图控制器中添加以下内容:
class RootViewController : UIViewController { private var _interfaceOrientation: UIInterfaceOrientation = .portrait override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return UIInterfaceOrientationMask(from: _interfaceOrientation) } override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { return _interfaceOrientation } override func viewDidLoad() { super.viewDidLoad() // Register for notifications NotificationCenter.default.addObserver(self, selector: #selector(RootViewController.handleInterfaceOrientationChangeRequestedNotification(_:)), name: .interfaceOrientationChangeRequested, object: nil) } deinit { NotificationCenter.default.removeObserver(self) } func handleInterfaceOrientationChangeRequestedNotification(_ notification: Notification) { guard let interfaceOrientation = notification.object as? UIInterfaceOrientation else { return } _interfaceOrientation = interfaceOrientation // Set device orientation // Important: // • Passing a UIDeviceOrientation here doesn't work, but passing a UIInterfaceOrientation does // • This is a hack, and could stop working at any moment UIDevice.current.setValue(interfaceOrientation.rawValue, forKey: "orientation") // Rotate the interface to the device orientation we just set UIViewController.attemptRotationToDeviceOrientation() } } private extension UIInterfaceOrientationMask { init(from interfaceOrientation: UIInterfaceOrientation) { switch interfaceOrientation { case .portrait: self = .portrait case .landscapeLeft: self = .landscapeLeft case .landscapeRight: self = .landscapeRight case .portraitUpsideDown: self = .portraitUpsideDown case .unknown: self = .portrait } } } extension Notification.Name { static let interfaceOrientationChangeRequested = Notification.Name(rawValue: "interfaceOrientationChangeRequested") }
确保在“部署信息”下检查所有界面方向:
在需要的地方请求界面方向更改:
NotificationCenter.default.post(name: .interfaceOrientationChangeRequested, object: UIInterfaceOrientation.landscapeRight)
基本的UINavigationController应该有下面的callback,以便子项可以决定他们想要的方向。
-(NSUInteger)supportedInterfaceOrientations { UIViewController *topVC = self.topViewController; return topVC.supportedInterfaceOrientations; } -(BOOL)shouldAutorotate { UIViewController *topVC = self.topViewController; return [topVC shouldAutorotate]; }
如果你只想要肖像模式,在iOS 9(Xcode 7)中,你可以:
- 去Info.plist
- select“支持的界面方向”项目
- 删除“风景(左主页button)”和“风景(右主页button)”
我和你有类似的问题。 我需要为某些屏幕locking设备方向(如“login”),并允许其他人旋转。
经过一些改变,下面的一些答案我做到了:
- 启用项目的Info.plist中的所有方向。
- 在那些需要设备不旋转的ViewController中禁用方向,就像在我的情况下的login屏幕一样。 我需要重写此VC中的
shouldAutorotate
方法:
-(BOOL)shouldAutorotate{ return NO; }
希望这会为你工作。
如果你有一个UIViewController应该保持肖像模式,只需添加这个覆盖,你就全部设置了。
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask { return UIInterfaceOrientationMask.Portrait }
最好的部分是这个视图显示时没有animation,它已经处于正确的方向。
这里是一个完整的工作例子iOS 7,8,9,10如何改变应用程序的方向,以目前的相反
Objective-C的
- (void)flipOrientation { NSNumber *value; UIInterfaceOrientation currentOrientation = [[UIApplication sharedApplication] statusBarOrientation]; if(UIInterfaceOrientationIsPortrait(currentOrientation)) { if(currentOrientation == UIInterfaceOrientationPortrait) { value = [NSNumber numberWithInt:UIInterfaceOrientationPortraitUpsideDown]; } else //if(currentOrientation == UIInterfaceOrientationPortraitUpsideDown) { value = [NSNumber numberWithInt:UIInterfaceOrientationPortrait]; } } else { if(currentOrientation == UIInterfaceOrientationLandscapeRight) { value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft]; } else //if(currentOrientation == UIInterfaceOrientationLandscapeLeft) { value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeRight]; } } [[UIDevice currentDevice] setValue:value forKey:@"orientation"]; [UIViewController attemptRotationToDeviceOrientation]; }
Swift 3
func flipOrientation() -> Void { let currentOrientation : UIInterfaceOrientation = UIApplication.shared.statusBarOrientation var value : Int = 0; if(UIInterfaceOrientationIsPortrait(currentOrientation)) { if(currentOrientation == UIInterfaceOrientation.portrait) { value = UIInterfaceOrientation.portraitUpsideDown.rawValue } else //if(currentOrientation == UIInterfaceOrientation.portraitUpsideDown) { value = UIInterfaceOrientation.portrait.rawValue } } else { if(currentOrientation == UIInterfaceOrientation.landscapeRight) { value = UIInterfaceOrientation.landscapeLeft.rawValue } else //if(currentOrientation == UIInterfaceOrientation.landscapeLeft) { value = UIInterfaceOrientation.landscapeRight.rawValue } } UIDevice.current.setValue(value, forKey: "orientation") UIViewController.attemptRotationToDeviceOrientation() }
试试这个和你的代码一起。
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation -(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
一旦用户select任何选项,然后调用此方法,因为用户可以处于横向模式,然后他可以在同一个视图控制器中只设置肖像模式,所以自动查看应该移动到肖像模式,所以在该button,
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration