Как заставить просмотр ориентации контроллера в iOS 8?

149

Перед прошивкой 8, мы использовали ниже кода в сочетании с supportedInterfaceOrientations и shouldAutoRotate методов делегата , чтобы заставить ориентацию приложения к какой - либо конкретной ориентации. Я использовал приведенный ниже фрагмент кода, чтобы программно повернуть приложение в нужную ориентацию. Во-первых, я меняю ориентацию строки состояния. И затем просто представление и немедленное отклонение модального вида поворачивает вид в желаемую ориентацию.

[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:YES];
UIViewController *c = [[UIViewController alloc]init];
[self presentViewController:vc animated:NO completion:nil];
[self dismissViewControllerAnimated:NO completion:nil];

Но это не работает в iOS 8. Кроме того, я видел некоторые ответы в переполнении стека, где люди предлагали, чтобы мы всегда избегали этого подхода с iOS 8 и далее.

Чтобы быть более конкретным, мое приложение является универсальным типом приложения. Всего три контроллера.

  1. Контроллер First View - он должен поддерживать все ориентации в iPad и только портрет (кнопка «Домой» вниз) в iPhone.

  2. Контроллер второго вида - он должен поддерживать только ландшафтное право в любых условиях

  3. Контроллер третьего вида - он должен поддерживать только ландшафтное право в любых условиях

Мы используем навигационный контроллер для навигации по страницам. В первом контроллере представления при нажатии кнопки мы помещаем второй в стек. Таким образом, когда прибывает второй контроллер представления, независимо от ориентации устройства, приложение должно блокироваться только в горизонтальной плоскости.

Ниже мой shouldAutorotateи supportedInterfaceOrientationsметоды во втором и третьем представлении контроллера.

-(NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskLandscapeRight;
}

-(BOOL)shouldAutorotate {
    return NO;
}

Есть ли какое-либо решение для этого или какой-либо лучший способ блокировки контроллера представления в определенной ориентации для iOS 8. Пожалуйста, помогите!

Рашми Ранджан Маллик
источник
Реализация методов, которые вы упомянули в представленном VC, как правило, должна работать (по крайней мере, это мой опыт работы с iOS 8). Возможно, ваша конкретная установка вызывает проблемы?
Владимир Гриценко
Может быть, я могу сделать вопрос немного яснее. Я немного отредактирую вопрос.
Рашми Ранджан Маллик
@VladimirGritsenko: Пожалуйста, проверьте сейчас. Я отредактировал это.
Рашми Ранджан Маллик
Код в вопросе не использует стек контроллера навигации, а скорее модальное представление, поэтому до сих пор не ясно, что именно вы делаете. Я скажу, что в нашем коде возвращение YES из shouldAutoRotate и возвращение желаемых ориентаций из supportInterfaceOrientations в представленном VC правильно ориентирует этот VC.
Владимир Гриценко
Ну, на самом деле это не провал, это просто большое изменение в концепции. Будь это хорошее изменение - это совсем другая тема.
Кеглунек

Ответы:

315

Для iOS 7 - 10:

Objective-C:

[[UIDevice currentDevice] setValue:@(UIInterfaceOrientationLandscapeLeft) forKey:@"orientation"];
[UINavigationController attemptRotationToDeviceOrientation];

Свифт 3:

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

Просто позвоните в - viewDidAppear:представленный контроллер представления.

Солнечный Шах
источник
61
Это не приватный API. Это небезопасное использование API. Вы не используете какие-либо частные методы, но используете «внутренние вещи». Если Apple изменит значение на «ориентация», произойдет сбой. Хуже того: если Apple меняет значение значения «ориентация», вы не знаете, что меняете, жестко настраивая значение.
sonxurxo
4
Чтобы отключить анимацию, положить [UIView setAnimationsEnabled:NO];в viewWillAppearи [UIView setAnimationsEnabled:YES];в viewDidAppear, связанных с : stackoverflow.com/a/6292506/88597
ohho
3
Хороший взлом, но проблема в том, что он не запускает didRotateFromInterfaceOrientation после установки нового значения ориентации (вздох)
loretoparisi
2
В iOS 9.2 это только изменение ориентации, но не блокировка.
Mark13426
2
Для всех, кто ведет себя так хорошо в 90% случаев и глючит в остальные 10% случаев, звоните после установки клавиши ориентации:[UINavigationController attemptRotationToDeviceOrientation];
Альберт Реншоу
93

Вращение ориентации немного сложнее, если вы находитесь внутри UINavigationControllerили UITabBarController. Проблема заключается в том, что если контроллер представления встроен в один из этих контроллеров, то контроллер навигации или панели вкладок имеет преимущество и принимает решения об авторотации и поддерживаемых ориентациях.

Я использую следующие 2 расширения для UINavigationController и UITabBarController, чтобы контроллеры представления, встроенные в один из этих контроллеров, могли принимать решения.

Дайте View Controllers мощь!

Swift 2.3

extension UINavigationController {
    public override func supportedInterfaceOrientations() -> Int {
        return visibleViewController.supportedInterfaceOrientations()
    }
    public override func shouldAutorotate() -> Bool {
        return visibleViewController.shouldAutorotate()
    }
}

extension UITabBarController {
    public override func supportedInterfaceOrientations() -> Int {
        if let selected = selectedViewController {
            return selected.supportedInterfaceOrientations()
        }
        return super.supportedInterfaceOrientations()
    }
    public override func shouldAutorotate() -> Bool {
        if let selected = selectedViewController {
            return selected.shouldAutorotate()
        }
        return super.shouldAutorotate()
    }
}

Swift 3

extension UINavigationController {
    open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return visibleViewController?.supportedInterfaceOrientations ?? super.supportedInterfaceOrientations
    }

    open override var shouldAutorotate: Bool {
        return visibleViewController?.shouldAutorotate ?? super.shouldAutorotate
    }
}

extension UITabBarController {
    open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        if let selected = selectedViewController {
            return selected.supportedInterfaceOrientations
        }
        return super.supportedInterfaceOrientations
    }

    open override var shouldAutorotate: Bool {
        if let selected = selectedViewController {
            return selected.shouldAutorotate
        }
        return super.shouldAutorotate
    }
}

Теперь вы можете переопределить supportedInterfaceOrientationsметод или вы можете переопределить shouldAutoRotateв контроллере представления, который хотите заблокировать, иначе вы можете пропустить переопределения в других контроллерах представления, которые вы хотите наследовать по умолчанию, согласно ориентации, указанной в списке приложений.

Отключить вращение

class ViewController: UIViewController {
    override func shouldAutorotate() -> Bool {
        return false
    }
}

Блокировка для определенной ориентации

class ViewController: UIViewController {
    override func supportedInterfaceOrientations() -> Int {
        return Int(UIInterfaceOrientationMask.Landscape.rawValue)
    }
}

Теоретически это должно работать для всех сложных иерархий контроллера представления, но я заметил проблему с UITabBarController. По некоторым причинам он хочет использовать значение ориентации по умолчанию. См. Следующий пост в блоге, если вы хотите узнать, как обойти некоторые из проблем:

Блокировка поворота экрана

Корей Хинтон
источник
1
Я знаю, что это очень старый пост, но куда бы вы поместили код расширения?
dwinnbrown
7
Отметка вниз для ответа Swift только на вопрос Objective-C.
Чарли Скотт-Скиннер
17
Это хорошее решение для Swift и ObjC. Не понимаю, почему люди голосуют. У вас есть идея, а затем написать код легко. Зачем жаловаться?
Чжао
2
@Krodak, в расширениях попробуйте поменять "-> Int" на "-> UIInterfaceOrientationMask". Сделал трюк для меня.
the_pantless_coder
2
Идея и код прекрасны, мне это нравится, но есть проблема при использовании UINavigationController и переходе от UIViewController в отображаемом в альбомной ориентации к тому, который должен отображаться в портретном. Любые идеи?
Кризис Грига
24

Вот что сработало для меня:

https://developer.apple.com/library//ios/documentation/UIKit/Reference/UIViewController_Class/index.html#//apple_ref/occ/clm/UIViewController/attemptRotationToDeviceOrientation

Вызовите это в вашем viewDidAppear: метод.

- (void) viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    [UIViewController attemptRotationToDeviceOrientation];
}
Винчил Бишоп
источник
3
Очень полезно, если устройство уже повернуто, и вам нужно повернуть контроллер вида
Авдюшин,
2
Отличный ответ. При использовании в сочетании с принятым ответом, это работает хорошо для меня каждый раз в Swift и iOS 9+.
AndyDunn
1
Хотя я думаю, что это не ответ на заданный вопрос, но это действительно помогло мне.
Абдуррахман Мубин Али
21

Я обнаружил, что если это представленный контроллер представления, вы можете переопределить preferredInterfaceOrientationForPresentation

Swift:

override func supportedInterfaceOrientations() -> Int {
  return Int(UIInterfaceOrientationMask.Landscape.rawValue)
}

override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
  return UIInterfaceOrientation.LandscapeLeft
}

override func shouldAutorotate() -> Bool {
  return false
}
Zipme
источник
4
Кажется, что принятый ответ просто вызывает изменение ориентации на ландшафт. То, что вы показали здесь, это то, как заставить контроллер представления находиться только в альбомной ориентации, и не влиять на представление контроллера представления (что именно то, что мне нужно). Спасибо.
Клифтон Лабрум
1
@CliftonLabrum ты сделал что-нибудь еще, чтобы заставить только пейзаж? Используя тот же код, контроллер представления все еще может поворачиваться в другую ориентацию.
Crashalot
Позже я понял, что - вы правы. Я еще не нашел исправления.
Клифтон Лабрум
1
Это сработало для меня. Я смог сохранить один View Controller в портретном режиме с помощью этого кода (заменив альбомную ориентацию на портретную). +1
Марк Баррассо
Да! Это работало и для меня в Xcode 7.3 и Swift 2.2. Но все же нужно определить приложение func для supportInterfaceOrientationsForWindow в AppDelegate.
charles.cc.hsu
16

Этот способ работает для меня в Swift 2 iOS 8.x:

PS (этот метод не требует переопределения функций ориентации, таких как mustautorotate на каждом viewController, только один метод на AppDelegate)

Отметьте «требуется полный экран» в общей информации о вашем проекте. введите описание изображения здесь

Итак, на AppDelegate.swift сделайте переменную:

var enableAllOrientation = false

Итак, поместите также эту функцию:

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
        if (enableAllOrientation == true){
            return UIInterfaceOrientationMask.All
        }
        return UIInterfaceOrientationMask.Portrait
}

Итак, в каждом классе вашего проекта вы можете установить эту переменную в viewWillAppear:

override func viewWillAppear(animated: Bool)
{
        super.viewWillAppear(animated)
        let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
        appDelegate.enableAllOrientation = true
}

Если вам нужно сделать выбор в зависимости от типа устройства, вы можете сделать это:

override func viewWillAppear(animated: Bool)
    {
        super.viewWillAppear(animated)
        let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
        switch UIDevice.currentDevice().userInterfaceIdiom {
        case .Phone:
        // It's an iPhone
           print(" - Only portrait mode to iPhone")
           appDelegate.enableAllOrientation = false
        case .Pad:
        // It's an iPad
           print(" - All orientation mode enabled on iPad")
           appDelegate.enableAllOrientation = true
        case .Unspecified:
        // Uh, oh! What could it be?
           appDelegate.enableAllOrientation = false
        }
    }
Алессандро Орнано
источник
очень хорошее объяснение
Михир Оза
11

Прежде всего - это плохая идея, в общем, что-то не так с архитектурой вашего приложения, но sh..t happens, если это так, вы можете попробовать сделать что-то вроде ниже:

final class OrientationController {

    static private (set) var allowedOrientation:UIInterfaceOrientationMask = [.all]

    // MARK: - Public

    class func lockOrientation(_ orientationIdiom: UIInterfaceOrientationMask) {
        OrientationController.allowedOrientation = [orientationIdiom]
    }

    class func forceLockOrientation(_ orientation: UIInterfaceOrientation) {
        var mask:UIInterfaceOrientationMask = []
        switch orientation {
            case .unknown:
                mask = [.all]
            case .portrait:
                mask = [.portrait]
            case .portraitUpsideDown:
                mask = [.portraitUpsideDown]
            case .landscapeLeft:
                mask = [.landscapeLeft]
            case .landscapeRight:
                mask = [.landscapeRight]
        }

        OrientationController.lockOrientation(mask)

        UIDevice.current.setValue(orientation.rawValue, forKey: "orientation")
    }
}

Чем в AppDelegate

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // do stuff
    OrientationController.lockOrientation(.portrait)
    return true
}

// MARK: - Orientation

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    return OrientationController.allowedOrientation
}

И всякий раз, когда вы хотите изменить ориентацию, делайте так:

OrientationController.forceLockOrientation(.landscapeRight)

Примечание. Иногда устройство может не обновляться после такого вызова, поэтому может потребоваться выполнить следующие действия.

OrientationController.forceLockOrientation(.portrait)
OrientationController.forceLockOrientation(.landscapeRight)

Вот и все

GBK
источник
9

Это должно работать с iOS 6 и выше, но я только протестировал это на iOS 8. Подкласс UINavigationControllerи переопределить следующие методы:

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
    return UIInterfaceOrientationLandscapeRight;
}

- (BOOL)shouldAutorotate {
    return NO;
}

Или спроси у видимого контроллера вид

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
    return self.visibleViewController.preferredInterfaceOrientationForPresentation;
}

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

и реализовать методы там.

Mojo66
источник
Я только что проверил это на своем приложении в Xcode 8.2.1 под управлением iOS 10.0, и оно работает. Мое игровое меню - это первый экран, который не вращается; все остальные виды вращаются. Отлично! Дали это один. Мне нужна была только функция «extendedInterfaceOrientationForPresentation», предоставленная Mojo66.
Филипп Борхес
9

Это отзыв на комментарии в ответе Сида Шаха , касающиеся того, как отключить анимацию с помощью:

[UIView setAnimationsEnabled:enabled];

Код:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:NO];
    [UIView setAnimationsEnabled:NO];

    // Stackoverflow #26357162 to force orientation
    NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeRight];
    [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:NO];
    [UIView setAnimationsEnabled:YES];
}
ohho
источник
Как я могу использовать это для Портрета.
Muju
6

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

- (BOOL)shouldAutorotate {
  id currentViewController = self.topViewController;

  if ([currentViewController isKindOfClass:[SecondViewController class]])
    return NO;

  return YES;
}

это отключит вращение в SecondViewController, но если вы нажмете свой SecondViewController, когда ваше устройство будет в портретной ориентации, то ваш SecondViewController появится в портретном режиме.

Предположим, что вы используете раскадровку. Вы должны создать ручной переход ( How to ) и в своем методе «onClick»:

- (IBAction)onPlayButtonClicked:(UIBarButtonItem *)sender {
  NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
  [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
  [self performSegueWithIdentifier:@"PushPlayerViewController" sender:self];
}

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

Lau
источник
6

По Xcode 8методам преобразуются в свойства, поэтому работает следующее Swift:

override public var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.portrait
}

override public var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
    return UIInterfaceOrientation.portrait
}

override public var shouldAutorotate: Bool {
    return true
}
Али Момен Сани
источник
Это блокирует ориентацию?
bnussey
1
@bnussey Я хотел предотвратить автоматическое вращение и быть всегда в portraitрежиме независимо от ориентации на iPad, shouldAutorotateвернув истину, я достиг этого.
Али Момен Сани
4

Я пробовал много решений, но одно из них работало так:

Нет необходимости редактировать info.plistв ios 8 и 9.

- (BOOL) shouldAutorotate {
    return NO;
}   

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return (UIInterfaceOrientationPortrait | UIInterfaceOrientationPortraitUpsideDown);
}

Возможные ориентации из документации Apple :

UIInterfaceOrientationUnknown

Ориентация устройства не может быть определена.

UIInterfaceOrientationPortrait

Устройство находится в портретном режиме, устройство находится в вертикальном положении, а кнопка «Домой» находится внизу.

UIInterfaceOrientationPortraitUpsideDown

Устройство находится в портретном режиме, но перевернуто, устройство находится в вертикальном положении, а кнопка «Домой» вверху.

UIInterfaceOrientationLandscapeLeft

Устройство находится в альбомной ориентации, устройство находится в вертикальном положении, а кнопка «Домой» расположена слева.

UIInterfaceOrientationLandscapeRight

Устройство находится в альбомной ориентации, устройство находится в вертикальном положении, а кнопка «Домой» находится на правой стороне.

hoogw
источник
3

Комбинация ответов Сидса и Корейса сработала для меня.

Расширение контроллера навигации:

extension UINavigationController {
    public override func shouldAutorotate() -> Bool {
        return visibleViewController.shouldAutorotate()
    }
}

Затем отключение поворота на одном просмотре

class ViewController: UIViewController {
    override func shouldAutorotate() -> Bool {
        return false
    }
}

И вращение в соответствующую ориентацию перед началом

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if (segue.identifier == "SomeSegue")
    {
        let value = UIInterfaceOrientation.Portrait.rawValue;
        UIDevice.currentDevice().setValue(value, forKey: "orientation")
    }
}
Миша
источник
Знаете ли вы, может ли это помочь моей проблеме, когда отображаемый контроллер представления находится в горизонтальной ориентации в течение секунды, прежде чем он поворачивается в портретную ориентацию, как это должно быть всегда? вопрос здесь: stackoverflow.com/questions/30693964/…
dwinnbrown
3

Верхнее решение выше:

let value = UIInterfaceOrientation.LandscapeLeft.rawValue
UIDevice.currentDevice().setValue(value, forKey: "orientation")

не работал для меня, когда я вызвал его в viewDidAppear представленного контроллера представления. Однако это сработало, когда я назвал его в preparForSegue в представляемом контроллере представления.

(Извините, репутации недостаточно, чтобы комментировать это решение, поэтому мне пришлось добавить его вот так)

Гвидо
источник
У меня это работает, но при переходе от контроллера ландшафтного вида к контроллеру портретного представления контроллер представления, который должен отображаться в портретном режиме, кратко отображается в альбомной ориентации, прежде чем вращаться самостоятельно. если кто-нибудь знает, как помочь, мой вопрос здесь: stackoverflow.com/questions/30693964/…
dwinnbrown
@dwinnbrown at viewDidAppear контроллер представления уже виден. Может, попробовать вместо viewDidLoad?
Crashalot
@Crashalot Я сейчас исправил это. Пожалуйста, посмотрите ответ, который я пометил как правильный.
dwinnbrown
@dwinnbrown ссылка на ваш вопрос мертва. Обновить? Спасибо!
Crashalot
@Crashalot сообщество удалило его, но я проголосовал за его удаление. Я дам вам знать в ближайшее время
dwinnbrown
3

[iOS9 +] Если кто-то перетащил сюда сюда, так как ни одно из вышеперечисленных решений не сработало, и если вы представляете представление, для которого вы хотите изменить ориентацию с помощью segue, вы можете проверить это.

Проверьте тип презентации вашего segue. Мой был «в текущем контексте». Когда я изменил его в полноэкранный режим, он работал.

Благодаря @GabLeRoux я нашел это решение.

  • Это изменение работает только в сочетании с решениями выше.
Гох
источник
2

Мои требования

  1. заблокировать все виды в портретном режиме
  2. использовать AVPlayerViewControllerдля воспроизведения видео

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

Сначала определите supportedInterfaceOrientationsForWindowвAppDelegate.swift

var portrait = true
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
    if portrait {
        return .Portrait
    } else {
        return .Landscape
    }
}

Во-вторых, в вашем главном контроллере вида определите следующие функции

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    print("\(#function)")
    return .Portrait
}

override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
    return .Portrait
}

override func shouldAutorotate() -> Bool {
    return false
}

Затем вам нужно подкласс AVPlayerViewController

class MyPlayerViewController: AVPlayerViewController {

    var size: CGSize?

    var supportedOrientationMask: UIInterfaceOrientationMask?
    var preferredOrientation: UIInterfaceOrientation?

    override func viewDidLoad() {
        super.viewDidLoad()

        if let size = size {
            if size.width > size.height {
                self.supportedOrientationMask =[.LandscapeLeft,.LandscapeRight]
                self.preferredOrientation =.LandscapeRight
            } else {
                self.supportedOrientationMask =.Portrait
                self.preferredOrientation =.Portrait
            }
        }
    }

Переопределите эти три функции в MyPlayerViewController.swift

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return self.supportedOrientationMask!
}

override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
    return self.preferredOrientation!
}

Поскольку пользователь может поворачивать устройство влево или вправо, нам нужно установить автоматический поворот на true

override func shouldAutorotate() -> Bool {
    return true
}

Наконец, создайте MyPlayerViewControllerэкземпляр в вашем контроллере представления и установите значение размера свойства.

let playerViewController = MyPlayerViewController()

// Get the thumbnail  
let thumbnail = MyAlbumFileManager.sharedManager().getThumbnailFromMyVideoMedia(......)

let size = thumbnail?.size
playerViewController.size = size

Начните свой игрок с должным videoUrl, затем назначьте своего игрока playerViewController. Удачного кодирования!

charles.cc.hsu
источник
2
- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    [UIViewController attemptRotationToDeviceOrientation];
}
Роман Солодяшкин
источник
1

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

- (void) viewWillAppear:(BOOL)animated
{
    [UIViewController attemptRotationToDeviceOrientation];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
    return (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}

-(BOOL)shouldAutorotate
{
    return NO;
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskLandscapeLeft;
}

В этом примере вам также необходимо установить для разрешенных ориентаций устройства значение «Пейзаж влево» в настройках проекта (или непосредственно в нем info.plist). Просто измените конкретную ориентацию, которую вы хотите использовать, если вы хотите что-то другое, чемLandscapeLeft.

Ключевым для меня был attemptRotationToDeviceOrientationзвонок viewWillAppear- без этого вид не вращался бы должным образом без физического вращения устройства.

ViperMav
источник
Устаревший метод.
Сакиб Омер
1

В соответствии с ответу Корея Хинтона

Swift 2.2:

extension UINavigationController {
    public override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
        return visibleViewController!.supportedInterfaceOrientations()
    }
    public override func shouldAutorotate() -> Bool {
        return visibleViewController!.shouldAutorotate()
    }
}


extension UITabBarController {
    public override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
        if let selected = selectedViewController {
            return selected.supportedInterfaceOrientations()
        }
        return super.supportedInterfaceOrientations()
    }
    public override func shouldAutorotate() -> Bool {
        if let selected = selectedViewController {
            return selected.shouldAutorotate()
        }
        return super.shouldAutorotate()
    }
}

Отключить вращение

override func shouldAutorotate() -> Bool {
    return false
}

Блокировка для определенной ориентации

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.Portrait
}
phnmnn
источник
1

Я попробовал несколько решений здесь, и важно понять, что именно контроллер корневого представления определяет, будет ли он вращаться или нет.

Я создал следующий проект target -c github.com/GabLeRoux/RotationLockInTabbedViewChild с рабочим примером того, TabbedViewControllerгде один дочерний вид может вращаться, а другой дочерний вид заблокирован в портретной ориентации.

Это не идеально, но работает, и та же идея должна работать для других видов корневых представлений, таких как NavigationViewController. :)

Дочернее представление блокирует родительскую ориентацию

GabLeRoux
источник
0

В соответствии с решением, представленным @ sid-sha, вы должны поместить все в viewDidAppear:метод, иначе вы не получите didRotateFromInterfaceOrientation:уволенный, так что-то вроде:

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
    if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
        interfaceOrientation == UIInterfaceOrientationLandscapeRight) {
        NSNumber *value = [NSNumber numberWithInt:interfaceOrientation];
        [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
    }
}
loretoparisi
источник
0

Мое решение

В AppDelegate:

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
    if let topController = UIViewController.topMostViewController() {
        if topController is XXViewController {
            return [.Portrait, .LandscapeLeft]
        }
    }
    return [.Portrait]
}

XXViewController это ViewController, который вы хотите поддерживать в ландшафтном режиме.

Тогда решение Санни Шаха будет работать у вас XXViewControllerна любой версии iOS:

let value = UIInterfaceOrientation.LandscapeLeft.rawValue
UIDevice.currentDevice().setValue(value, forKey: "orientation")

Это служебная функция, чтобы найти самый верхний ViewController.

extension UIViewController {

    /// Returns the current application's top most view controller.
    public class func topMostViewController() -> UIViewController? {
        let rootViewController = UIApplication.sharedApplication().windows.first?.rootViewController
        return self.topMostViewControllerOfViewController(rootViewController)
    }



    /// Returns the top most view controller from given view controller's stack.
    class func topMostViewControllerOfViewController(viewController: UIViewController?) -> UIViewController? {
        // UITabBarController
        if let tabBarController = viewController as? UITabBarController,
           let selectedViewController = tabBarController.selectedViewController {
            return self.topMostViewControllerOfViewController(selectedViewController)
        }

        // UINavigationController
        if let navigationController = viewController as? UINavigationController,
           let visibleViewController = navigationController.visibleViewController {
            return self.topMostViewControllerOfViewController(visibleViewController)
        }

        // presented view controller
        if let presentedViewController = viewController?.presentedViewController {
            return self.topMostViewControllerOfViewController(presentedViewController)
        }

        // child view controller
        for subview in viewController?.view?.subviews ?? [] {
            if let childViewController = subview.nextResponder() as? UIViewController {
                return self.topMostViewControllerOfViewController(childViewController)
            }
        }

        return viewController
    }

}
дуань
источник
0

Используйте это для блокировки ориентации контроллера вида, протестированного на IOS 9:

// Зафиксируем ориентацию вправо

-(UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskLandscapeRight;
}

-(NSUInteger)navigationControllerSupportedInterfaceOrientations:(UINavigationController *)navigationController {
    return UIInterfaceOrientationMaskLandscapeRight;
}
robegamesios
источник
0

У меня та же проблема, и я трачу на нее столько времени. Так что теперь у меня есть свое решение. Моя настройка приложения только поддерживает портретную ориентацию. Однако некоторые экраны в моем приложении должны иметь только альбомную ориентацию. Я исправляю это с помощью переменной isShouldRotate в AppDelegate . И функция в AppDelegate :

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int {
    if isShouldRotate == true {
        return Int(UIInterfaceOrientationMask.Landscape.rawValue)
    }
    return Int(UIInterfaceOrientationMask.Portrait.rawValue)
}

И, наконец, когда ViewControllerA требуется ландшафтное состояние. Просто сделать это: прежде , чем толкающий / настоящее к ViewControllerA правопреемник isShouldRotate к истинному . Не забывайте, когда выдвигаете / отклоняете этот контроллер, присваивайте isShouldRotate значение false при viewWillDisappear .

подветренный
источник
0

Для меня VC верхнего уровня необходим для реализации переопределения ориентации. Использование VC вниз по стеку не будет иметь никакого эффекта, если верхний VC не реализует.

VC-main
    |
    -> VC 2
        |
        -> VC 3

Только VC-Main слушают, по сути, в моем тестировании.

bduhbya
источник
0

Похоже, что даже ты здесь так много ответов, никого не было достаточно для меня. Я хотел форсировать ориентацию, а затем при возвращении вернуться к ориентации устройства, но [UIViewController attemptRotationToDeviceOrientation];просто не сработало. Что также усложнило, так это то, что я добавил shouldAutorotate в false, основываясь на каком-то ответе, и не смог получить желаемых эффектов для правильного поворота назад во всех сценариях.

Вот что я сделал:

Перед нажатием контроллера в вызове в его конструкторе инициализации это:

_userOrientation = UIDevice.currentDevice.orientation;
[UIDevice.currentDevice setValue:@(UIInterfaceOrientationPortrait) forKey:@"orientation"];
[self addNotificationCenterObserver:@selector(rotated:)
                               name:UIDeviceOrientationDidChangeNotification];

Поэтому я сохраняю последнюю ориентацию устройства и регистрируюсь на событие изменения ориентации. Событие изменения ориентации простое:

- (void)rotated:(NSNotification*)notification {
    _userOrientation = UIDevice.currentDevice.orientation;
}

И при исчезновении вида я просто возвращаюсь к любой ориентации, которую я имею как userOreintation:

- (void)onViewDismissing {
    super.onViewDismissing;
    [UIDevice.currentDevice setValue:@(_userOrientation) forKey:@"orientation"];
    [UIViewController attemptRotationToDeviceOrientation];
}

И это должно быть там тоже:

- (BOOL)shouldAutorotate {
    return true;
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskPortrait;
}

А также навигационный контроллер должен делегировать shouldAutorotate и supportInterfaceOrientations, но, как я полагаю, большинство людей уже имеют.

PS: Извините, я использую некоторые расширения и базовые классы, но имена довольно значимы, так что концепция понятна, сделает еще больше расширений, потому что теперь это не слишком красиво.

Renetik
источник