如何在 iOS 7 中以编程方式设置设备方向?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20987249/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 23:01:42  来源:igfitidea点击:

How do I programmatically set device orientation in iOS 7?

iosxcodeios7autolayoutautorotate

提问by John Stewart

I am working on an iPad app, using AutoLayout, where if the user enables a certain mode ("heads-up" mode), I want to support only portrait (or portrait upside down) orientation, and furthermore, if the device is in landscape, I'd like to automatically switch to portrait mode.

我正在使用 AutoLayout 开发 iPad 应用程序,如果用户启用某种模式(“抬头”模式),我只想支持纵向(或纵向颠倒)方向,此外,如果设备处于横向,我想自动切换到纵向模式。

In the top view controller, I have the following:

在顶视图控制器中,我有以下内容:

- (NSUInteger) supportedInterfaceOrientations {
    if (self.modeHeadsUp) {
        return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown;
    } else {
        return UIInterfaceOrientationMaskAll;
    }
}

- (BOOL) shouldAutorotate {
    return TRUE;
}

Based on answers I've seen elsewhere here, the answer seemsto be that I should use "application setStatusBarOrientation". Therefore, in the method where the user has selected "heads-up" mode, I have included:

根据我在这里其他地方看到的答案,答案似乎是我应该使用“application setStatusBarOrientation”。因此,在用户选择“单挑”模式的方法中,我包含了:

    UIApplication *application = [UIApplication sharedApplication];
    [application setStatusBarOrientation:UIInterfaceOrientationPortrait
                                animated:YES];

However, this simply doesn't seem to do anything. While I can physically move the device to get it to rotate into portrait, it doesn't do so automatically.

然而,这似乎没有任何作用。虽然我可以物理移动设备以使其旋转为纵向,但它不会自动执行此操作。

In fact, when in landscape mode after running the above code to attempt to programmatically set the orientation, when I query the application "statusBarOrientation" with the following code, it remains at "4" for landscape:

事实上,在运行上述代码后在横向模式下尝试以编程方式设置方向时,当我使用以下代码查询应用程序“statusBarOrientation”时,横向仍为“4”:

UIApplication *application = [UIApplication sharedApplication];
int orientation = [application statusBarOrientation];
self.movesTextView.text = [NSString stringWithFormat:@"ORIENTATION %d", orientation];

It seemed like maybe autolayout wasn't being triggered with the setStatusBarOrientation, so I attempted to add this code after, to no effect:

似乎自动布局没有被 setStatusBarOrientation 触发,所以我尝试在之后添加此代码,但没有效果:

    [super updateViewConstraints];
    [self.view updateConstraints];

I realize Apple wants to leave device orientation in the hands of the user. However, I'd like to be able to support landscape mode when not in "heads-up" mode.

我意识到 Apple 希望将设备方向掌握在用户手中。但是,我希望能够在不处于“单挑”模式时支持横向模式。

Am I missing something to be able to force orientation change?

我是否错过了能够强制改变方向的东西?

回答by Sunny Shah

For iOS 7 & 8:

对于 iOS 7 和 8:

Objective-C:

目标-C:

NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
[[UIDevice currentDevice] setValue:value forKey:@"orientation"];

Swift 3+:

斯威夫特 3+:

let value = UIInterfaceOrientation.landscapeLeft.rawValue
UIDevice.current.setValue(value, forKey: "orientation")

I call it in - viewDidAppear:.

我调用它- viewDidAppear:

回答by Arpan Dixit

Use this. Perfect solution to orientation problem..ios7 and earlier

用这个。定位问题的完美解决方案..ios7 及更早版本

[[UIDevice currentDevice] setValue:
    [NSNumber numberWithInteger: UIInterfaceOrientationPortrait]
        forKey:@"orientation"];

回答by snak

You need to call attemptRotationToDeviceOrientation (UIViewController)to make the system call your supportedInterfaceOrientationswhen the condition has changed.

当条件发生变化时,您需要调用attemptRotationToDeviceOrientation (UIViewController)以使系统调用您supportedInterfaceOrientations的。

回答by Rikco

NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft]; [[UIDevice currentDevice] setValue:value forKey:@"orientation"];

does work but you have to return shouldAutorotate with YES in your view controller

确实有效,但您必须在视图控制器中使用 YES 返回 shouldAutorotate

- (BOOL)shouldAutorotate
{
    return self.shouldAutoRotate;
}

But if you do that, your VC will autorotate if the user rotates the device... so I changed it to:

但是如果你这样做,如果用户旋转设备,你的 VC 将自动旋转......所以我将其更改为:

@property (nonatomic, assign) BOOL shouldAutoRotate;

- (BOOL)shouldAutorotate
{
    return self.shouldAutoRotate;
}

and I call

我打电话

- (void)swithInterfaceOrientation:(UIInterfaceOrientation)orientation
{
    self.rootVC.shouldAutoRotate = YES;

    NSNumber *value = [NSNumber numberWithInt: orientation];
    [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
}

to force a new orientation with a button-click. To set back shouldAutoRotate to NO, I added to my rootVC

通过单击按钮强制新方向。要将 shouldAutoRotate 设置回 NO,我添加到我的 rootVC

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
    self.shouldAutoRotate = NO;
}

PS: This workaround does work in all simulators too.

PS:此解决方法也适用于所有模拟器。

回答by SamSmart

This works for me on Xcode6 & 5.

这在Xcode6 和 5对我有用。

- (BOOL)shouldAutorotate {
    return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
    return (UIInterfaceOrientationMaskPortrait);
}

回答by kjam

The only way that worked for me is presenting dummy modal view controller.

对我有用的唯一方法是呈现虚拟模式视图控制器。

UIViewController* dummyVC = [[UIViewController alloc] init];
dummyVC.view = [[UIView alloc] init];
[self presentModalViewController:dummyVC animated:NO];
[self dismissModalViewControllerAnimated:NO];

Your VC will be asked for updated interface orientations when modal view controller is dismissed.

当模态视图控制器被关闭时,您的 VC 将被要求更新界面方向。

Curious thing is that UINavigationController does exactly this when pushing/popping child view controllers with different supported interface orientations (tested on iOS 6.1, 7.0).

奇怪的是 UINavigationController 在推送/弹出具有不同支持界面方向的子视图控制器时正是这样做的(在 iOS 6.1、7.0 上测试)。

回答by Torre Lasley

If you have a UIViewController that should stay in Portrait mode, simply add this override and you're all set.

如果你有一个 UIViewController 应该保持在纵向模式,只需添加这个覆盖就可以了。

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.Portrait
}

The best part is there is no animation when this view is shown, it's just already in the correct orientation.

最好的部分是显示此视图时没有动画,它只是已经处于正确的方向。

回答by Niels

This solution lets you force a certain interface orientation, by temporarily overriding the value of UIDevice.current.orientationand then asking the system to rotate the interface to match the device's rotation:

此解决方案可让您通过暂时覆盖 的值UIDevice.current.orientation然后要求系统旋转界面以匹配设备的旋转来强制特定的界面方向:

Important: This is a hack, and could stop working at any moment

重要提示:这是一个黑客行为,随时可能停止工作

Add the following in your app's root view controller:

在应用的根视图控制器中添加以下内容:

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")
}

Make sure all interface orientations are checked under "Deployment Info":

确保在“部署信息”下检查所有界面方向:

Interface Orientations

界面方向

Request interface orientation changes where you need them:

在您需要的地方请求界面方向更改:

NotificationCenter.default.post(name: .interfaceOrientationChangeRequested, object: UIInterfaceOrientation.landscapeRight)

回答by Carlos Eugênio Torres

If you want to lock the main view of your app to portrait, but want to open popup views in landscape, and you are using tabBarController as rootViewController as I am, you can use this code on your AppDelegate.

如果您想将应用程序的主视图锁定为纵向,但想以横向方式打开弹出视图,并且您像我一样使用 tabBarController 作为 rootViewController,则可以在 AppDelegate 上使用此代码。

AppDelegate.h

AppDelegate.h

@interface AppDelegate : UIResponder <UIApplicationDelegate, UITabBarControllerDelegate>

@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) UITabBarController *tabBarController;

@end

AppDelegate.m

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;
}

It works very well.

它运作良好。

In your viewController you want to be presented in landscape, you simply use the following:

在您希望以横向方式呈现的 viewController 中,您只需使用以下内容:

- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskLandscape;
}

- (BOOL)shouldAutorotate {
    return YES;
}

回答by niuNaruto

  1. Add this statement into AppDelegate.h

    //whether to allow cross screen marker 
    @property (nonatomic, assign) allowRotation BOOL;
    
  2. Write down this section of code into AppDelegate.m

    - (UIInterfaceOrientationMask) application: (UIApplication *) supportedInterfaceOrientationsForWindow: application (UIWindow *) window {
        If (self.allowRotation) {
            UIInterfaceOrientationMaskAll return;
        }
        UIInterfaceOrientationMaskPortrait return;
    }
    
  3. Change the allowRotationproperty of delegate app

  1. 将此语句添加到 AppDelegate.h

    //whether to allow cross screen marker 
    @property (nonatomic, assign) allowRotation BOOL;
    
  2. 把这部分代码写成 AppDelegate.m

    - (UIInterfaceOrientationMask) application: (UIApplication *) supportedInterfaceOrientationsForWindow: application (UIWindow *) window {
        If (self.allowRotation) {
            UIInterfaceOrientationMaskAll return;
        }
        UIInterfaceOrientationMaskPortrait return;
    }
    
  3. 更改allowRotation委托应用的属性