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

如何在iOS 7中以编程方式设置设备方向?,ios,xcode,ios7,autolayout,autorotate,Ios,Xcode,Ios7,Autolayout,Autorotate,我正在使用AutoLayout开发一个iPad应用程序,如果用户启用某个模式(“抬头”模式),我只想支持纵向(或纵向倒置)方向,而且,如果设备处于横向,我想自动切换到纵向模式 在俯视图控制器中,我有以下内容: - (NSUInteger) supportedInterfaceOrientations { if (self.modeHeadsUp) { return UIInterfaceOrientationMaskPortrait | UIInterfaceOrient

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

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

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

- (BOOL) shouldAutorotate {
    return TRUE;
}
- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskLandscape;
}

- (BOOL)shouldAutorotate {
    return YES;
}
根据我在其他地方看到的答案,答案似乎是我应该使用“应用程序setStatusBaroOrientation”。因此,在用户选择“抬头”模式的方法中,我包括:

    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];
似乎SetStatusBaroOrientation没有触发autolayout,所以我尝试在之后添加此代码,但没有任何效果:

    [super updateViewConstraints];
    [self.view updateConstraints];
我意识到苹果想把设备定位权交给用户。但是,我希望在不处于“平视”模式时能够支持横向模式

我是否错过了强制改变方向的功能?

对于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")

我在
-viewdide中调用它:

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

-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation  

-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
一旦用户选择任何选项,然后调用此方法,因为用户可以处于横向模式,然后他可以在同一视图控制器中仅设置纵向模式,所以自动将视图移动到纵向模式,以便在该按钮中调用此方法

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

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

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

AppDelegate.h

@interface AppDelegate : UIResponder <UIApplicationDelegate, UITabBarControllerDelegate>

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

@end
它工作得很好

在要在横向视图中显示的viewController中,只需使用以下命令:

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

- (BOOL) shouldAutorotate {
    return TRUE;
}
- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskLandscape;
}

- (BOOL)shouldAutorotate {
    return YES;
}

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

UIViewController* dummyVC = [[UIViewController alloc] init];
dummyVC.view = [[UIView alloc] init];
[self presentModalViewController:dummyVC animated:NO];
[self dismissModalViewControllerAnimated:NO];
当模态视图控制器被解除时,您的VC将被要求更新界面方向


奇怪的是,当推/弹出具有不同支持界面方向的子视图控制器(在iOS 6.1和7.0上测试)时,UINavigationController正是这样做的。定位问题的完美解决方案..ios7及更早版本

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

这在
Xcode
6和5上对我有效

- (BOOL)shouldAutorotate {
    return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
    return (UIInterfaceOrientationMaskPortrait);
}
可以工作,但必须在视图控制器中返回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:此解决方案也适用于所有模拟器。

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

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

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

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

  • 去Info.plist
  • 选择“支持的接口方向”项
  • 删除“横向(左主按钮)”和“横向(右主按钮)”

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

在做了一些更改并遵循以下一些答案后,我通过以下方式完成了:

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

  • 在需要设备不旋转的视图控制器中禁用方向,如我的案例中的登录屏幕。我需要在此VC中重写
    shouldAutorotate
    方法:
-(BOOL)应自动旋转{
返回否;
}

希望这对你有用

  • 将此语句添加到
    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
    属性


  • 如果您有一个UIViewController,它应该保持在纵向模式,只需添加这个覆盖,就可以全部设置好

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

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

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

    这里是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()
    }
    

    这对我很有效

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

    对于像我这样努力让@Sunny Shah接受ipad工作的人来说。您需要在项目设置中设置“需要全屏”复选框。请注意,这将阻止你的应用程序在多任务模式下工作,这可能是可以接受的,也可能是不可以接受的


    2020年Swift 5:

    override var supportedInterfaceOrientations:UIInterfaceOrientationMask {
        return .portrait
    }
    

    我不太清楚您的建议是什么,但在iOS7中,shouldAutorotateToInterfaceOrientation似乎被弃用,取而代之的是shouldAutorotate,我已经实现了它。对不起,我的错误。仅使用shouldAutorotate和-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientati