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

76

我正在开发一个iPad应用程序,使用AutoLayout。如果用户启用了某种模式(“悬浮”模式),我希望仅支持竖屏(或倒置的竖屏)方向,并且如果设备处于横屏状态,我想自动切换到竖屏模式。

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

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

- (BOOL) shouldAutorotate {
    return TRUE;
}
根据我在其他地方看到的答案,似乎应该使用"application setStatusBarOrientation"。因此,在用户选择“heads-up”模式的方法中,我已包含如下内容:
    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];

我知道苹果希望将设备方向掌握在用户手中。不过,当处于非“heads-up”模式时,我希望能支持横屏模式。

我是否遗漏了什么来强制更改方向?

18个回答

2
对于像我这样在iPad上无法让 @Sunny Shah 的答案正常工作的人来说,你需要在项目设置中勾选“需要全屏”复选框。请注意,这将防止您的应用程序在多任务模式下工作,这可能是可以接受的,也可能不是。

enter image description here


1
基本的UINavigationController应该有以下回调函数,以便子项可以决定他们想要的方向。
-(NSUInteger)supportedInterfaceOrientations {
    UIViewController *topVC = self.topViewController;
    return topVC.supportedInterfaceOrientations;
}

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

1
这是一个适用于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()
}

这个解决方案使用反射技术,因为iOS没有/显示任何公共方法来实现这个目标,所以我们必须通过反射来完成它。 - ddb
最终,我们正在修改苹果不希望我们修改的东西:UIDeviceorientation 属性是只读的。你曾经因为这段代码被拒绝过吗? - Sunil Chauhan
抱歉,我无法回答,因为我使用此代码片段的应用程序已在iTunes之外发布,您是否尝试提交类似的代码? - ddb

1
如果你只想要竖屏模式,在iOS 9(Xcode 7)中,你可以:
  • 前往 Info.plist
  • 选择 "Supported interface orientations" 选项
  • 删除 "Landscape(left home button)" 和 "Landscape(right home button)"

enter image description here


1

我曾经遇到与你类似的问题。我需要在某些屏幕(例如登录)锁定设备方向,并允许其他屏幕旋转。

通过进行一些更改并按照下面的一些答案,我做到了:

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

enter image description here

  • 在那些我需要设备不旋转的视图控制器中禁用方向,比如在我的登录界面。我需要在这个视图控制器中重写shouldAutorotate方法:

-(BOOL)shouldAutorotate{ return NO; }

希望这对你有用。


0

这对我完美地起作用了...

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

0

尝试将此代码与您的代码一起使用。

-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation  

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

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

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

我不太确定你在暗示什么,但是shouldAutorotateToInterfaceOrientation在iOS7中已经被弃用,应该使用shouldAutorotate代替,而我已经实现了这个方法。 - John Stewart
抱歉,我的错误。应该只使用shouldAutorotate和-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration。 - Charan Giri
我在选择 heads-up 模式的方法中添加了 [self willRotateToInterfaceOrientation:UIInterfaceOrientationPortrait duration:ROTATE_VIEW_DELAY];,替代了上面 Sunny Shah 的 objc_msgSend 答案。不幸的是,对显示器没有影响。据我了解,“willrotate”被调用时,显示器即将旋转,响应用户物理移动设备。 - John Stewart
@John Stewart 我们可以独立地调用这个方法... 但是告诉我你在这个方法中编写的代码是什么。如果可能的话,你能否更新你的问题,包括你为方向编写的所有代码(你使用的所有方法)。 - Charan Giri
Charan Giri - 我创建了一个简单的测试项目来演示:https://github.com/johnstewart/RotateTest。该项目是一个简单的iPad应用程序,具有一个ImageView和一个开关,用于打开和关闭“仅竖屏”模式。我从一个空的视图项目开始,并添加了这个属性:`@property (nonatomic) bool modePortraitOnly;` - John Stewart
显示剩余2条评论

0

2020年 Swift 5:

override var supportedInterfaceOrientations:UIInterfaceOrientationMask {
    return .portrait
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接