it-swarm.com.ru

Как программно установить ориентацию устройства в iOS 7?

Я работаю над приложением для iPad, используя AutoLayout, где, если пользователь включает определенный режим (режим «голова-вверх»), я хочу поддерживать только портретную (или портретную вверх ногами) ориентацию и, более того, если устройство находится в пейзаж, я хотел бы автоматически переключиться в портретный режим.

В контроллере вида сверху у меня есть следующее:

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

Казалось, что, возможно, autolayout не был запущен с помощью setStatusBarOrientation, поэтому я попытался добавить этот код после, безрезультатно:

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

Я понимаю, что Apple хочет оставить ориентацию устройства в руках пользователя. Тем не менее, я хотел бы иметь возможность поддерживать ландшафтный режим, когда не в режиме «один на один». 

Я что-то упускаю, чтобы заставить меня изменить ориентацию?

70
John Stewart

Для iOS 7 и 8:

Objective-C:

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

Свифт 3+:

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

Я называю это в - viewDidAppear:.

194
Sunny Shah

Использовать этот. Идеальное решение проблемы ориентации. IOS7 и ранее

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

Вам нужно позвонить attemptRotationToDeviceOrientation (UIViewController) , чтобы система вызывала ваш supportedInterfaceOrientations, когда условие изменилось.

10
snak
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: этот обходной путь работает и во всех симуляторах.

4
Rikco

Это работает для меня Xcode 6 и 5.

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

Единственный способ, который сработал для меня, представляет фиктивный контроллер модального вида.

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).

3
kjam

Это решение позволяет принудительно задать определенную ориентацию интерфейса, временно переопределив значение 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)
3
Niels
  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 приложения делегата

2
niuNaruto

Если у вас есть UIViewController, который должен оставаться в портретном режиме, просто добавьте это переопределение, и все готово.

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

Самое приятное, что при отображении этого вида анимация отсутствует, просто он уже в правильной ориентации.

2
Torre Lasley

Если вы хотите заблокировать основной вид вашего приложения для портрета, но хотите открыть всплывающие виды в альбомной ориентации, и вы используете 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;
}
2
Carlos Eugênio Torres

Базовый UINavigationController должен иметь обратный вызов ниже, чтобы дочерние элементы могли решить, какую ориентацию они хотят.

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

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

вот пример ПОЛНОЙ РАБОТЫ для 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()
}
1
ddb

У меня была похожая проблема, чем у вас. Мне нужно заблокировать ориентацию устройства для некоторых экранов (например, Логин) и разрешить поворот на других.

После нескольких изменений и следующих ответов я сделал это:

  • Включение всех ориентаций в Info.plist проекта.

 enter image description here

  • Отключение ориентации в тех ViewControllers, где мне нужно, чтобы устройство не вращалось, как на экране входа в моем случае. Мне нужно переопределить метод shouldAutorotate в этом VC:

-(BOOL)shouldAutorotate{ return NO; }

Надеюсь, это сработает для вас.

1
David de Tena

Если вы хотите только портретный режим, в iOS 9 (Xcode 7) вы можете: 

  • Переход к Info.plist
  • Выберите пункт «Поддерживаемые ориентации интерфейса»
  • Удалить "Пейзаж (левая кнопка домой)" и "Пейзаж (правая кнопка домой)"

 enter image description here

1
Danilo Raspa

Это сработало у меня отлично ....

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

Для таких, как я, которые боролись за то, чтобы @Sunny Shah принял ответ на работу на iPad. Вам необходимо установить флажок «Требуется полный экран» в настройках проекта. Обратите внимание, что это помешает вашему приложению работать в многозадачном режиме, который может быть или не быть приемлемым.

 enter image description here

0
leandrodemarco

Попробуйте это вместе с вашим кодом.

-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation  

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

после того, как пользователь выберет любую опцию, затем вызовите этот метод, потому что пользователь может быть в ландшафтном режиме, а затем он может установить только портретный режим в том же контроллере вида, поэтому автоматически вид должен быть переведен в портретный режим, поэтому в этой кнопке acton вызовите эту

-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
0
Charan Giri