Отключить вращение для контроллера представления в контроллере навигации

Во-первых, это не дубликат. Я рассмотрел все вопросы, связанные с этим, на SO, и ни один из них не работает для меня. Надеюсь, это только потому, что я новичок в разработке iOS, но подозреваю, что в моем случае это невозможно. Я приложил изображение с обведенным контроллером представления, для которого я хочу отключить вращение.

Я уже пробовал: создать подкласс контроллера представления, для которого я хочу отключить вращение, и использовать метод shouldAutoRotate, установив для него значение NO. По-видимому, это не работает, потому что контроллер навигации определяет, могут ли вращаться его контроллеры представления. Итак, я создал подкласс UINavigationController и использовал этот класс в раскадровке вместо контроллера навигации по умолчанию. В этом классе я установил shouldAutoRotate на НЕТ. Это все еще не работает. Не знаю, что я делаю неправильно.

Когда я расширяю контроллер корневого представления с помощью моего класса контроллера представления с shouldAutoRotate, установленным в NO, он отключает вращение... для всего приложения. Это не то, чего я хочу. Я хочу, чтобы вращение было отключено только для контроллера представления, обведенного на картинке.

введите здесь описание изображения

Заранее спасибо!


person user2900772    schedule 19.01.2014    source источник
comment
на это много раз отвечали в разных решениях, но ответ такой же и для вашей ситуации. Проверьте мой ответ для более подробной информации.   -  person CoolMonster    schedule 19.01.2014


Ответы (7)


Добавьте свой AppDelegate.h

@property (nonatomic , assign) bool blockRotation;

AppDelegate.m

-(NSUInteger)application:(UIApplication *)application       supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if (self.blockRotation) {
    return UIInterfaceOrientationMaskPortrait;
}
return UIInterfaceOrientationMaskAll;
}

В представлении контроллера, который вы хотите отключить вращение

- (void)viewDidLoad
{
 [super viewDidLoad];
    AppDelegate* shared=[UIApplication sharedApplication].delegate;
    shared.blockRotation=YES;
}

-(void)viewWillDisappear:(BOOL)animated{
  AppDelegate* shared=[UIApplication sharedApplication].delegate;
  shared.blockRotation=NO;

  }

Swift 4.2 и более поздние версии:

В вашем AppDelegate.swift:

var blockRotation = false

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    if blockRotation {
        return .portrait
    }
    return .all
}

В вашем viewController:

override func viewDidLoad() {
    super.viewDidLoad()
    AppDelegate.shared.blockRotation = true
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    AppDelegate.shared.blockRotation = false
}
person Ozgur Sahin    schedule 18.10.2014
comment
Даже если это выглядит как взлом, это решает проблему для меня. Только когда вы повернули устройство, когда был виден другой ViewController, ViewController остается повернутым. Просто замечание: в вашем AppDelegate вы назвали его blockRotation, но в ViewController allowRotation. - person Christian; 03.01.2015
comment
Небольшое замечание для тех, у кого эта работа не работает на iPad/iOS 10, в настройках проекта установите Requires full screen на YES. - person CharlieReed; 16.05.2017

Спасибо @ozgur за исправление, которое сработало для меня. Я бы «проголосовал за», но, видимо, я недостаточно хорош (что бы там ни было!), чтобы голосовать за то, работает ли исправление или нет. Во всяком случае, вот он в Swift:

В AppDelegate.swift:

class AppDelegate: UIResponder, UIApplicationDelegate {


var blockRotation: Bool = false

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int {

    if (self.blockRotation) {
        println("supportedInterfaceOrientations - PORTRAIT")
        return Int(UIInterfaceOrientationMask.Portrait.rawValue)
    } else {
        println("supportedInterfaceOrientations - ALL")
        return Int(UIInterfaceOrientationMask.All.rawValue)
    }
}

В ViewController, который вы хотите заблокировать, добавьте в свой класс UIApplicationDelegate...

class LoginViewController: UIViewController, UITextFieldDelegate, UIApplicationDelegate {

а затем создайте ссылку на AppDelegate...

var appDelegate = UIApplication.sharedApplication().delegate as AppDelegate

В viewDidLoad установите appDelegate.blockRotation = true:

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.

    appDelegate.blockRotation = true

}

В viewWillAppear установите ориентацию, чтобы заставить устройство использовать выбранную ориентацию (в данном примере — портретную):

override func viewWillAppear(animated: Bool) {

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

}

Затем в viewWillDisappear или в prepareForSegue установите appDelegate.blockRotation = false:

override func viewWillDisappear(animated: Bool) {
    appDelegate.blockRotation = false
}

Это сработало для меня в этом точном сценарии (несколько контроллеров представления в контроллере навигации) после многих часов чтения других решений на этом сайте. Еще раз спасибо @ozgur - я бы проголосовал ваш ответ если бы я мог!

Счастливых троп!

person AT3D    schedule 17.04.2015
comment
Всем привет. Отличный ответ! Ваш ответ единственный, который мне помог. Однако я задавался вопросом об одном. В симуляторе содержимое не поворачивается автоматически после изменения blockRotation, он по-прежнему требует, чтобы виртуальное устройство было изменено на альбомную ориентацию, прежде чем оно зафиксируется в правильной ориентации. Вы знаете, как я могу заставить содержимое измениться на альбомную ориентацию? Спасибо! - person Rstew; 28.06.2015
comment
Привет @Stew - E. Большое спасибо. Мне потребовались ЧАСЫ, чтобы выяснить это, поэтому я рад, что это сэкономило и вам время. Что касается принудительного вращения, я не пробовал, но вы можете попробовать следующее в viedDidAppear: let value = UIInterfaceOrientation.LandscapeLeft.rawValue UIDevice.currentDevice().setValue(value, forKey: "orientation") - person AT3D; 24.07.2015
comment
Работает и в viewWillAppear. - person AT3D; 05.08.2015
comment
Вам не нужно реализовывать UIApplicationDelegate или что-то еще. Просто используйте (UIApplication.sharedApplication().delegate as! AppDelegate). blockRotation = true - person Allison; 01.05.2016

Для тех из вас, кто использует Swift 2, вы можете следовать ответу Андре, но на первом этапе используйте приведенный ниже код в своем AppDelegate.swift:

class AppDelegate: UIResponder, UIApplicationDelegate {


var blockRotation: Bool = false

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {

    if (self.blockRotation) {
        print("supportedInterfaceOrientations - PORTRAIT")
        return UIInterfaceOrientationMask.Portrait
    } else {
        print("supportedInterfaceOrientations - ALL")
        return UIInterfaceOrientationMask.All
    }
}

поддерживаемыйInterfaceOrientationsForWindow: теперь возвращает UIInterfaceOrientationMask вместо Int.

person Charlie    schedule 23.09.2015

Вы должны проверить в корневом контроллере представления, разрешено ли вращение в текущем верхнем контроллере, и вернуть YES или NO в методе supportedInterfaceOrientations. Таким образом, в вашем корневом контроллере должен быть такой код (адаптируйте код к вашему случаю):

- (NSUInteger)supportedInterfaceOrientations
{    
    return [self.navigationController.topViewController supportedInterfaceOrientations];
}

Затем в каждом контроллере представления добавьте поддерживаемые ориентации интерфейса, например:

- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}
person Sergey Demchenko    schedule 19.01.2014
comment
Когда я помещаю этот код в свой корневой контроллер представления, он отключает вращение для каждого контроллера представления, даже если я добавляю в код поддерживаемые интерфейсы ориентации. Есть идеи? - person user2900772; 19.01.2014
comment
Ваша цель - делегировать решение о поддерживаемом вращении конкретному контроллеру. Я считаю, что ваш код внутри supportInterfaceOrientation должен выглядеть следующим образом: return [‹выбранный контроллер в меню›.navigationController.topViewControllersupportInterfaceOrientations]; - person Sergey Demchenko; 19.01.2014
comment
Хорошо, в моем корневом контроллере представления у меня есть - (NSUInteger)supportedInterfaceOrientations { return [self.navigationController.topViewControllersupportInterfaceOrientations]; } И в DashboardViewController у меня есть -- (NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskLandscape; } Дело в том, что даже когда этот метод вызывается в контроллере представления, он все еще застревает в портретной ориентации, хотя я говорю UIInterfaceOrientationMaskLandscape; - person user2900772; 19.01.2014
comment
Я не знаю точно иерархию VC в вашем проекте, поэтому можете ли вы сказать мне, как вы можете получить доступ к текущему видимому DashboardViewController внутри корневого контроллера представления? - person Sergey Demchenko; 19.01.2014
comment
Ok. Как вы можете видеть на картинке, у меня есть контроллер корневого представления слайд-меню. Затем он переходит к контроллеру представления меню, а оттуда каждый из пунктов меню имеет контроллер навигации. Таким образом, каждый из отдельных пунктов меню имеет свой собственный навигационный контроллер. Я использую return self.navigationController.topViewController. - person user2900772; 19.01.2014
comment
Вы добавили меню vc как дочернее в корневой vc или вставили его в навигационный контроллер корневого vc? - person Sergey Demchenko; 19.01.2014
comment
Я сделал это в раскадровке, это переход левого меню слайда от контроллера корневого представления меню слайдов к контроллеру представления меню. - person user2900772; 19.01.2014
comment
Переход является настраиваемым, поэтому вы каким-то образом обрабатываете этот пользовательский переход в своем коде :) - person Sergey Demchenko; 19.01.2014
comment
В этом проблема? Не очень понимаю, почему все это не работает. - person user2900772; 19.01.2014

В моем случае есть 3 контроллера вида:
- контроллер первого вида: портретный
- контроллер второго вида: альбомный справа (имеет контроллер навигации и был представлен контроллером первого вида)
- контроллер третьего вида: портретный (имеет навигационный контроллер и был нажат вторым контроллером представления)
И это мое решение в Swift 3:
--------------------- ---------------
В AppDelegate:
— добавьте это свойство, чтобы сохранить настройки

private var orientation: UIInterfaceOrientationMask = .portrait

-Затем создайте функцию для установки поворота для вашего устройства:

func rotateScreen(orientation: UIInterfaceOrientationMask) {
    self.orientation = orientation
    var value = 0;
    if orientation == .landscapeRight {
        value = UIInterfaceOrientation.landscapeRight.rawValue
    }else {
        value = UIInterfaceOrientation.portrait.rawValue
    }
    UIDevice.current.setValue(value, forKey: "orientation")
}

- Наконец, реализуйте метод ориентации поддержки:

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

--------------------------------
Затем вы можете вызывать так, прежде чем отображать контроллер представления назначения

(UIApplication.shared.delegate as! AppDelegate).rotateScreen(orientation: .landscapeRight)

Например, в моем случае: когда пользователь нажимает кнопку на первом, чтобы представить второй, я сделаю так

(UIApplication.shared.delegate as! AppDelegate).rotateScreen(orientation: .landscapeRight)
self.present(navigation, animated: true, completion: nil)

А кнопку закрытия у Второго сделаю вот так

(UIApplication.shared.delegate as! AppDelegate).rotateScreen(orientation: .portrait)
self.dismiss(animated: true, completion: nil)

Это все! Вы не могли возражать против использования навигационного контроллера или нет. Надеюсь, это поможет вам, ребята ^__^!

person Heo Đất Hades    schedule 22.09.2017

Категория UINavigationController+Rotation

Когда вы используете контроллер навигации SupportedInterfaceOrientaions из ViewController, не будет работать добавление этой категории в ваш проект также получит ответ от вашего viewController, а не только NavigationController.

person CoolMonster    schedule 19.01.2014
comment
Это не работает. Это не та ситуация, которую вы описываете, поэтому она не работает. - person user2900772; 19.01.2014

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

    let theViewController = UIViewController()
    if let navController = theViewController as? UINavigationController {
        navController.delegate = self
    }

Затем добавьте это расширение: extension PlaySplashViewController: UINavigationControllerDelegate {

func navigationControllerSupportedInterfaceOrientations(_ navigationController: UINavigationController) -> UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.portrait
}

}

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

person Hiram Elguezabal    schedule 21.10.2019