Как принудительно настроить ориентацию контроллера вида в iOS 8?
до iOS 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. Кроме того, я видел некоторые ответы в Stack overflow, где люди предлагали нам всегда избегать этого подхода с iOS 8 и далее.
чтобы быть более конкретным, мое приложение является универсальным типом приложения. Есть три контроллера в общей сложности.
первый вид-контроллер - он должен поддерживать все ориентации в iPad и только портрет (главная кнопка вниз) в айфон.
контроллер второго вида - он должен поддерживать только ландшафт прямо во всех условиях
третий вид-контроллер - он должен поддерживать только ландшафт прямо во всех условиях
мы используем навигационный контроллер для навигации по странице. Из первого контроллера вида, на действие нажатия кнопки, мы нажимаем второй на стеке. Итак, когда второй контроллер вида прибывает, независимо от ориентации устройства, приложение должно фиксироваться только в альбомной ориентации.
ниже shouldAutorotate и supportedInterfaceOrientations методы во втором и третьем контроллере вида.
-(NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskLandscapeRight;
}
-(BOOL)shouldAutorotate {
return NO;
}
есть ли какое-либо решение для этого или какой-либо лучший способ блокировки контроллера вида в определенной ориентации для iOS 8. Пожалуйста, помогите!!
24 ответов:
для iOS 7 - 10:
Цель-C:
[[UIDevice currentDevice] setValue:@(UIInterfaceOrientationLandscapeLeft) forKey:@"orientation"]; [UINavigationController attemptRotationToDeviceOrientation];Swift 3:
let value = UIInterfaceOrientation.landscapeLeft.rawValue UIDevice.current.setValue(value, forKey: "orientation") UINavigationController.attemptRotationToDeviceOrientation()просто позвоните в
- viewDidAppear:представленного контроллера представления.
ориентация вращения немного сложнее, если вы находитесь внутри
UINavigationControllerилиUITabBarController. Проблема заключается в том, что если контроллер вида встроен в один из этих контроллеров, то контроллер навигации или панели вкладок имеет приоритет и принимает решения об авторотации и поддерживаемых ориентациях.я использую следующие 2 расширения на UINavigationController и UITabBarController, чтобы контроллеры представления, встроенные в один из этих контроллеров, могли сделать решения.
дайте регуляторы взгляда силу!
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в контроллере вида, который вы хотите заблокировать, иначе вы можете оставить переопределения в других контроллерах вида, которые вы хотите наследовать поведение ориентации по умолчанию, указанное в plist вашего приложенияотключить Вращение
class ViewController: UIViewController { override func shouldAutorotate() -> Bool { return false } }блокировка в определенной ориентации
class ViewController: UIViewController { override func supportedInterfaceOrientations() -> Int { return Int(UIInterfaceOrientationMask.Landscape.rawValue) } }теоретически это должно работать для всех сложных иерархий контроллера представления, но я заметил проблему с UITabBarController. По какой-то причине он хочет использовать значение ориентации по умолчанию. См. следующее сообщение в блоге, Если вы заинтересованы в получении информации о том, как обойти некоторые из проблем:
Это то, что сработало для меня:
вызовите его в своем методе viewDidAppear:.
- (void) viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; [UIViewController attemptRotationToDeviceOrientation]; }
я обнаружил, что если это представленный контроллер вида, вы можете переопределить
preferredInterfaceOrientationForPresentationSwift:
override func supportedInterfaceOrientations() -> Int { return Int(UIInterfaceOrientationMask.Landscape.rawValue) } override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation { return UIInterfaceOrientation.LandscapeLeft } override func shouldAutorotate() -> Bool { return false }
этот способ работы для меня в Swift 2 iOS 8.x:
PS (этот метод не требует переопределения функций ориентации, таких как shouldautorotate на каждом 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 } }
Это должно работать с 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; }и реализовать методы там.
это обратная связь с комментариями в ответ Сид Шаха, о том, как отключить анимацию, используя:
[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]; }
прежде всего-это плохая идея, в общем, что-то не так происходит с вашей архитектурой приложения, но,
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") } }чем, в
AppDelegatefunc 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)вот и все
On
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 }
Если вы используете navigationViewController вы должны создать свой собственный суперкласс для этого и переопределить:
- (BOOL)shouldAutorotate { id currentViewController = self.topViewController; if ([currentViewController isKindOfClass:[SecondViewController class]]) return NO; return YES; }это отключит вращение в SecondViewController но если вы толкать свои SecondViewController когда устройство находится в портретной ориентации, то ваш SecondViewController появится в портретном режиме.
предположим, что вы используете раскадровки. Вы должны создать ручной переход (как к) и в вашем методе "onClick":
- (IBAction)onPlayButtonClicked:(UIBarButtonItem *)sender { NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft]; [[UIDevice currentDevice] setValue:value forKey:@"orientation"]; [self performSegueWithIdentifier:@"PushPlayerViewController" sender:self]; }это заставит альбомную ориентацию перед вашим суперклассом отключить функцию авторотации.
Я пробовал много решений, но тот, который работал на следующее:
нет необходимости редактировать
info.plistв ios 8 и 9.- (BOOL) shouldAutorotate { return NO; } - (UIInterfaceOrientationMask)supportedInterfaceOrientations { return (UIInterfaceOrientationPortrait | UIInterfaceOrientationPortraitUpsideDown); }возможные ориентации из документации Apple:
UIInterfaceOrientationUnknown
ориентация устройства не может быть определен.
UIInterfaceOrientationPortrait
в устройство находится в портретном режиме, при этом устройство удерживается в вертикальном положении и главная кнопка на дне.
UIInterfaceOrientationPortraitUpsidedown
устройство находится в портретном режиме, но вверх ногами, удерживая устройство с вертикально и кнопка "Домой" вверху.
UIInterfaceOrientationLandscapeLeft
устройство находится в ландшафтном режиме, при этом устройство удерживается в вертикальном положении и главная кнопка слева сторона.
UIInterfaceOrientationLandscapeRight
устройство находится в ландшафтном режиме, при этом устройство удерживается в вертикальном положении и главная кнопка на правой стороне.
комбинация ответов Sids и Koreys сработала для меня.
расширение навигационного контроллера:
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") } }
верхнее решение выше:
let value = UIInterfaceOrientation.LandscapeLeft.rawValue UIDevice.currentDevice().setValue(value, forKey: "orientation")не на меня, когда я назвал его в viewDidAppear представленного контроллера представления. Однако это сработало, когда я вызвал его в preparForSegue в контроллере представления представления.
(извините, недостаточно очков репутации, чтобы прокомментировать это решение, поэтому мне пришлось добавить его так)
мои требования
- блокировка всех видов в портретном режиме
- использовать
AVPlayerViewControllerдля воспроизведения видеокогда видео воспроизводится, если это пейзаж, то позвольте экрану вращать пейзаж вправо и пейзаж влево. Если это портрет, то заблокировать вид только в портретном режиме.
во-первых, определить
supportedInterfaceOrientationsForWindowнаAppDelegate.swiftvar 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 }тогда вам нужно подкласс
AVPlayerViewControllerclass 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.swiftoverride func supportedInterfaceOrientations() -> UIInterfaceOrientationMask { return self.supportedOrientationMask! } override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation { return self.preferredOrientation! }потому что пользователь может повернуть устройство ландшафт влево или вправо, нам нужно установить auto rotate, чтобы быть 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. Счастливого кодирования!
- (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; [UIViewController attemptRotationToDeviceOrientation]; }
По данным ответ Кори Хинтона
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 }
я попробовал несколько решений здесь, и важно понять, что это корневой контроллер представления, который будет определять, будет ли он вращаться или нет.
Я создал следующее С проект github.com/GabLeRoux/RotationLockInTabbedViewChild с рабочим примером
TabbedViewControllerгде один дочерний вид разрешен поворот, а другой дочерний вид заблокирован в портрете.это не идеально, но это работает и та же идея должен работать для других видов корневых представлений, таких как
NavigationViewController. :)
[iOS 9 охота+] Если кто-то тащил весь путь сюда, поскольку ни одно из вышеперечисленных решений не работало, и если вы представляете вид, который вы хотите изменить ориентацию на переход, возможно, вы захотите проверить это.
Проверьте тип презентации вашего segue. Мой был над текущим контекстом'. Когда я изменил его на полноэкранный режим, он работал.
благодаря @GabLeRoux, я нашел это решение.
- это изменение работает только в сочетании с выше решений.
согласно решению, показанному @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"]; } }
мое решение
на
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 } }
используйте это для блокировки ориентации контроллера вида, протестированного на IOS 9:
/ / блокировка ориентации в альбомной ориентации вправо
-(UIInterfaceOrientationMask)supportedInterfaceOrientations { return UIInterfaceOrientationMaskLandscapeRight; } -(NSUInteger)navigationControllerSupportedInterfaceOrientations:(UINavigationController *)navigationController { return UIInterfaceOrientationMaskLandscapeRight; }
кажется, все еще есть некоторые дебаты о том, как лучше всего выполнить эту задачу, поэтому я подумал, что поделюсь своим (рабочим) подходом. Добавьте следующий код
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- без этого вид не будет правильно вращаться без физического вращения устройства.
У меня та же проблема и тратить так много времени на это. Так что теперь у меня есть свое решение. Мои настройки приложения просто поддерживают только портрет.Однако некоторые экраны в моем приложении должны иметь только ландшафт.Я исправляю это с помощью переменной isShouldRotate at AppDelegate. И функция в AppDelegate:
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int { if isShouldRotate == true { return Int(UIInterfaceOrientationMask.Landscape.rawValue) } return Int(UIInterfaceOrientationMask.Portrait.rawValue) }и, наконец, когда a ViewControllerA нужно состояние ландшафта. Просто сделайте это:перед нажать/присутствует до ViewControllerA назначение isShouldRotate до правда. Не забывайте, когда pop / отклонить этот контроллер назначить isShouldRotate до false at viewWillDisappear.
для меня VC верхнего уровня необходим для реализации переопределений ориентации. Использование VC вниз по стеку не будет иметь никакого эффекта, если верхний VC не реализует.
VC-main | -> VC 2 | -> VC 3слушается только VC-Main, по существу, в моем тестировании.


Comments