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

时间:2014-01-08 04:47:31

标签: ios xcode ios7 autolayout autorotate

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

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

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

- (BOOL) shouldAutorotate {
    return TRUE;
}

基于我在其他地方看到的答案,答案似乎是我应该使用“application setStatusBarOrientation”。因此,在用户选择“抬头”模式的方法中,我已经包括:

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

我意识到Apple希望将设备方向放在用户手中。但是,我希望能够在不进行“抬头”模式时支持横向模式。

我错过了一些能够强制改变方向的东西吗?

18 个答案:

答案 0 :(得分:190)

对于iOS 7& 8:

目标-C:

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

Swift 3 +:

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

我在- viewDidAppear:中调用它。

答案 1 :(得分:20)

使用它。定位问题的完美解决方案..原点及之前的

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

答案 2 :(得分:10)

当条件发生变化时,您需要致电attemptRotationToDeviceOrientation (UIViewController)让系统调用您的supportedInterfaceOrientations

答案 3 :(得分:4)

这适用于Xcode 6& 5。

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

答案 4 :(得分:4)

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

确实有效,但你必须在视图控制器中返回shouldAutorotate并带有YES

- (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"];
}

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

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

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

答案 5 :(得分:3)

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

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

当解除模态视图控制器时,将要求VC更新接口方向。

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

答案 6 :(得分:3)

此解决方案允许您通过暂时覆盖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")
}

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

Interface Orientations

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

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

答案 7 :(得分:2)

如果您想将应用程序的主视图锁定为纵向,但想要在横向上打开弹出视图,并且您正在使用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;
}

答案 8 :(得分:2)

  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属性

答案 9 :(得分:2)

如果您的UIViewController应该保持纵向模式,只需添加此覆盖,即可全部设置。

pip

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

答案 10 :(得分:1)

基础UINavigationController应具有以下回调,以便子项可以决定他们想要的方向。

-(NSUInteger)supportedInterfaceOrientations {
    UIViewController *topVC = self.topViewController;
    return topVC.supportedInterfaceOrientations;
}

-(BOOL)shouldAutorotate {
   UIViewController *topVC = self.topViewController;
   return [topVC shouldAutorotate];
}

答案 11 :(得分:1)

如果您只想要纵向模式,在iOS 9(Xcode 7)中,您可以:

  • 转到Info.plist
  • 选择&#34;支持的界面方向&#34;项目
  • 删除&#34;风景(左主页按钮)&#34;和#34;风景(右主页按钮)&#34;

enter image description here

答案 12 :(得分:1)

我遇到了与你类似的问题。我需要为某些屏幕(如Login)锁定设备方向,并允许在其他屏幕上旋转。

经过一些修改并按照下面的一些答案后,我做了:

  • 在项目的Info.plist中启用所有方向。

enter image description here

  • 在我需要设备不旋转的那些ViewControllers中禁用方向,就像在我的情况下的登录屏幕中一样。我需要在此VC中覆盖shouldAutorotate方法:

-(BOOL)shouldAutorotate{ return NO; }

希望这对你有用。

答案 13 :(得分:1)

这里是iOS 7,8,9,10的完整工作示例如何将应用方向更改为当前相反的

<强>目标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()
}

答案 14 :(得分:0)

2020 Swift 5:

override var supportedInterfaceOrientations:UIInterfaceOrientationMask {
    return .portrait
}

答案 15 :(得分:0)

对于像我这样努力获得@Sunny Shah的人,他们接受了在iPad上工作的答案。您需要在项目设置中选中“要求全屏显示”复选框。请注意,这将阻止您的应用在多任务处理模式下工作,这可能是可接受的。

enter image description here

答案 16 :(得分:0)

这对我很有帮助....

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

答案 17 :(得分:0)

尝试使用您的代码。

-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation  

-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration

一旦用户选择任何选项然后调用此方法,因为用户可以处于横向模式,然后他可以在同一个视图控制器中设置只有纵向模式,因此自动视图应该移动到纵向模式,因此在该按钮中调用此

-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration