Як змусити орієнтацію контролера перегляду в iOS 8?


149

Перед iOS 8 ми використовували код нижче в поєднанні з підтримуванимиInterfaceOrientations та методами делегування 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. Контролер першого перегляду - він повинен підтримувати всі орієнтації в iPad та лише портрет (кнопка додому) в iPhone.

  2. Контролер другого перегляду - Він повинен підтримувати лише право пейзажу в будь-яких умовах

  3. Контролер третього перегляду - Він повинен підтримувати лише право пейзажу в будь-яких умовах

Ми використовуємо контролер навігації для навігації по сторінках. З першого контролера перегляду, при натисканні кнопки, ми натискаємо другий на стек. Отже, коли приходить контролер другого виду, незалежно від орієнтації пристрою, додаток має фіксуватися лише в правій частині пейзажу.

Нижче наведено мої shouldAutorotateта supportedInterfaceOrientationsметоди в другому та третьому контролерах подання.

-(NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskLandscapeRight;
}

-(BOOL)shouldAutorotate {
    return NO;
}

Чи є рішення щодо цього чи будь-якого кращого способу блокування контролера перегляду, зокрема орієнтації на iOS 8. Будь ласка, допоможіть !!


Реалізація згаданих вами методів у представленому ПК повинна, як правило, працювати (принаймні, це мій досвід роботи в iOS 8). Можливо, ваша конкретна установка викликає проблеми?
Володимир Гриценко

Можливо, я можу зробити це питання трохи зрозумілішим. Я трохи відредагую питання.
Rashmi Ranjan mallick

@VladimirGritsenko: Будь ласка, перевірте зараз. Я це відредагував.
Маллік Рашмі Ранджан

Код у запитанні не використовує стек навігаційного контролера, а скоріше модальну презентацію, тому все ще не ясно, що саме ви робите. Я скажу, що в нашому коді повернення YES від shouldAutoRotate та повернення бажаних орієнтацій з підтримуванихInterfaceOrientations у представленому VC належним чином орієнтує цей VC.
Володимир Гриценко

Ну, це насправді невдало, це лише велика зміна концепції. Чи це гарна зміна - це зовсім інша тема.
Kegluneq

Відповіді:


315

Для iOS 7 - 10:

Завдання-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, щоб переглядати контролери, вбудовані в один з цих контролерів, для прийняття рішень.

Надайте контролерам виду живлення!

Швидкий 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()
    }
}

Швидкий 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, що відображається в пейзажі, до того, який повинен бути відображений в портреті. Будь-які ідеї?
crisGriega

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
Дуже корисно, якщо пристрій уже обернено і вам потрібно повернути контролер перегляду
avdyushin

2
Чудова відповідь. Якщо використовуватись у поєднанні з прийнятою відповіддю, для мене це працює щоразу у Swift та iOS 9+.
AndyDunn

1
Хоча я думаю, що це не відповідь на поставлене запитання, але це мені справді допомогло.
Абдуррахман Мубін Алі

21

Я виявив, що якщо це представлений контролер перегляду, ви можете його перекрити preferredInterfaceOrientationForPresentation

Швидкий:

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

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

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

4
Здається, що прийнята відповідь просто викликає зміну орієнтації на ландшафт. Тут ви показали, як змусити контролер подання зображень бути лише в ландшафті, а не впливати на представлений контролер подання (що саме те, що мені потрібно). Дякую.
Кліфтон Лабрум

1
@CliftonLabrum Ви робили щось інше, щоб змусити лише пейзаж? Використовуючи той самий код, контролер перегляду все ще може повернутись до іншої орієнтації.
Crashalot

Пізніше я зрозумів, що - ти прав. Я ще не знайшов виправлення.
Кліфтон Лабрум

1
Це працювало для мене. Мені вдалося зберегти один контролер перегляду в режимі «Портрет» за допомогою цього коду (замінивши «Пейзаж» на «Портрет»). +1
Марк Баррассо

Так! Це працювало і для мене в Xcode 7.3 та Swift 2.2. Але все ж потрібно визначити функціональну програму для підтримуванихInterfaceOrientationsForWindow в AppDelegate.
charles.cc.hsu

15

Цей спосіб працює для мене в Swift 2 iOS 8.x:

PS (цей метод не вимагає переосмислити функції орієнтації, такі як слідавтоматизуватись на кожному viewController, лише один метод у AppDelegate)

Поставте прапорець "потрібен повний екран" у загальній інформації про проект. введіть тут опис зображення

Отже, на AppDelegate.swift зробіть змінну:

var enableAllOrientation = false

Отже, покладіть також цю функцію:

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

Отже, у кожному класі вашого проекту ви можете встановити цей var у 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)

Це все


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

і реалізувати там методи.


Я щойно тестував це на своєму додатку в Xcode 8.2.1 під управлінням iOS 10.0, і він працює. Моє ігрове меню - це перший екран, який не обертається; всі інші погляди обертаються. Ідеально! Дав його вгору. Мені потрібна була лише функція «переважнеInterfaceOrientationForPresentation», надана 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];
}

Як я можу це використовувати для портрета.
Муджу

6

Якщо ви використовуєте navigationViewController, ви повинні створити свій власний надклас для цього та замінити:

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

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

  return YES;
}

це призведе до відключення обертання в SecondViewController, але якщо ви натискаєте на SecondViewController, коли ваш пристрій перебуває в орієнтації на портрет, то SecondViewController з'явиться в портретному режимі.

Припустимо, що ви використовуєте раскадровку. Ви повинні створити вручну segue ( як це зробити ) та у вашому методі "onClick":

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

Це змусить орієнтацію на пейзаж перед тим, як ваш суперклас відключить функцію автоматичного повороту.


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.plistios 8 і 9 не потрібно редагувати .

- (BOOL) shouldAutorotate {
    return NO;
}   

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

Можливі орієнтації з документації Apple :

UIInterfaceOrientationUnknown

Не можна визначити орієнтацію пристрою.

UIInterfaceOrientationPor Portrait

Пристрій перебуває в портретному режимі, пристрій тримається вертикально, а кнопка додому - внизу.

UIInterfaceOrientationPor PortraitUpsideDown

Пристрій перебуває в портретному режимі, але догори дном, пристрій тримається вертикально, а кнопка додому вгорі.

UIInterfaceOrientationLandscapeLeft

Пристрій знаходиться в ландшафтному режимі, пристрій тримається вертикально, а кнопка додому - зліва.

UIInterfaceOrientationLandscapeRight

Пристрій знаходиться в ландшафтному режимі, пристрій тримається вертикально, а кнопка дому - праворуч.


3

Поєднання відповідей Сіда та Корейса працювало на мене.

Розширення навігаційного контролера:

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

Потім вимкнення обертання в одному Перегляді

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

І обертаючись до відповідної орієнтації перед segue

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 в 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!
}

Оскільки користувач може обертати пейзаж пристрою ліворуч або пейзаж праворуч, нам потрібно встановити автоматичне обертання таким чином, щоб воно було істинним

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. Щасливого кодування!



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- без того перегляд не буде належним чином обертатися без фізичного обертання пристрою.


Застарілий метод.
Сакіб Омер

1

Згідно з Корея Гінтона

Швидкий 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
}

1

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

Я створив такий об'єктивний проект github.com/GabLeRoux/RotationLockInTabbedViewChild з робочим прикладом того, TabbedViewControllerколи одному дочірньому представленню дозволено обертатися, а інший дочірній погляд зафіксовано в портреті.

Це не ідеально, але він працює і така ж ідея повинна працювати і для інших видів кореневих поглядів, таких як NavigationViewController. :)

Дитячий погляд блокує орієнтацію батьків


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

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, який ви бажаєте підтримувати в ландшафтному режимі.

Тоді рішення Sunny Shah буде працювати у вашій 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;
}

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 до істинного . Не забувайте, коли поп / відхилити це призначення контролера будеShouldRotate to false при viewWillDisappear .


0

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

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

Прослуховується тільки VC-Main, по суті, в моєму тестуванні.


0

Схоже, навіть у вас тут стільки відповідей, нікого мені не вистачило. Я хотів примусити орієнтацію, а потім, повертаючись назад, поверніться до орієнтації пристрою, але [UIViewController attemptRotationToDeviceOrientation];просто не працював. Що також зробило все складне, це те, що я додав повиненAutorotate до помилкового, грунтуючись на певній відповіді, і не міг отримати бажаних ефектів, щоб правильно повернутись назад у всіх сценаріях.

Отже, це я зробив:

Перш ніж натиснути контролер на виклик у його init конструкторі, це:

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

Тому я зберігаю останню орієнтацію пристрою та реєструюсь на подію зміни орієнтації. Подія зміни орієнтації проста:

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

А на вигляд відхилення я просто змушуюсь повернутися до будь-якої орієнтації, якою я користувачу

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

І це теж повинно бути там:

- (BOOL)shouldAutorotate {
    return true;
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskPortrait;
}

А також контролер навігації повинен делегуватися доAutorotate та підтримуєтьсяInterfaceOrientations, але в це я вважаю більшість людей.

PS: Вибачте, я використовую деякі розширення та базові класи, але назви є досить значущими, тому концепція зрозуміла, зробить ще більше розширень, тому що зараз це не так вже й багато.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.