Възстановяване на автоматичното завъртане след налагане на ориентация в Swift

В моето приложение за iPhone имам изглед, който искам да показвам само в портретен режим. Когато навигирате до този изглед, той трябва автоматично да се показва в портретен изглед. Когато навигирате, ориентацията трябва да се върне към предишната или, ако ориентацията на устройството се е променила, да се адаптира към това. Мога да намеря информация за налагане на ориентация и предотвратяване на автоматично завъртане. Не можах да намеря нищо относно как да променя обратно правилната ориентация, след като навигирам извън този изглед.

Така че идеята ми беше да

  1. запазете първоначалната ориентация (запазете в currentOrientation)
  2. абонирайте се за събитие за промяна на ориентацията, за да следите промените в ориентацията, докато съдържанието е заключено към портрет (актуализация currentOrientation)
  3. когато напускате изгледа, възстановете правилната ориентация, като използвате стойността currentOrientation.

Редактиране (кодът вече е премахнат): Освен че не работи, това беше опасен начин, тъй като използваше широко неподдържани API.


Редактиране:

Вярвам, че този въпрос сега може да се сведе до следното:

  1. Има ли документиран, поддържан начин за налагане на ориентацията на интерфейса независимо от ориентацията на устройството? setValue(UIInterfaceOrientation.Portrait.rawValue, forKey: "orientation") е препоръчван много пъти на SO и другаде, но наистина изглежда, че е неподдържан хак.

  2. Има ли документиран, поддържан начин за актуализиране на ориентацията на интерфейса към ориентацията на устройството? Това би било необходимо за „възстановяване“ от принудителната ориентация на интерфейса в друг изглед, без да се налага да задействате автоматично завъртане чрез завъртане на устройството напред и назад.

Поддържат се supportedInterfaceOrientations() и shouldAutorotate(). Но те ще заключат ориентацията на интерфейса само след като устройството е обърнато в тази позиция. Те не предотвратяват грешна първоначална ориентация.

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


person jerry    schedule 02.07.2015    source източник
comment
Това, което правите, за да зададете ориентацията, е недокументирано и не се поддържа. Вероятно е по-лесно просто да добавите поддръжка за пейзаж за този един изглед, отколкото да се опитвате да контролирате завъртанията.   -  person Aaron Brager    schedule 03.07.2015
comment
В идеалния случай системата ще се погрижи за правилната ориентация, след като напусне изгледа със заключена ориентация, но няма да го направи. Има ли по-прост начин да се постигне това? Създаването на пейзажна версия на този изглед не е опция.   -  person jerry    schedule 03.07.2015
comment
Трябва да изтриете бита setValue(… forKey: "orientation"), защото той е недокументиран и се поддържа. Трябва да можете да постигнете това, което искате, като използвате supportedInterfaceOrientations(), shouldAutorotate() и attemptRotationToDeviceOrientation().   -  person Aaron Brager    schedule 03.07.2015
comment
Просто любопитно (без да съм аргументиран) - защо създаването на пейзажна версия на изгледа не е опция? Интересувам се от UX, върху който работите.   -  person Aaron Brager    schedule 03.07.2015
comment
Благодаря, Арън, ще си поиграя още малко и ще се опитам да измисля по-просто решение, използвайки поддържаните интерфейси. Да, липсата на пейзаж е дизайнерско решение. Това е приложение за различни платформи, което стартира в Windows и Android, където този изглед съответно е хъб страница или изглед на пейджър. Има фоново изображение на цял екран и е почти ядрото на приложението. Нямаше да изглежда добре в хоризонтален изглед, дори ако успеех да пренаредя всички елементи. Пълно препроектиране на този изглед, напр. използвайки раздели, смятам, че приложението ще загуби своя идентификатор (марка).   -  person jerry    schedule 03.07.2015
comment
Още един момент: setValue() се използва за принудително изглед към портрет, когато е отворен, докато устройството е в пейзаж. supportedInterfaceOrientations() и shouldAutoRotate() не се погрижиха за това. Трябваше първо да завъртя устройството в портретен режим и след това изгледът беше заключен в портретен режим. Намерих няколко препратки към метода setValue(), което, разбира се, не го прави добра практика. Как иначе мога да го постигна?   -  person jerry    schedule 03.07.2015


Отговори (1)


Имах подобен проблем, с изключение на това, че имах нужда от един контролер за изглед, който да работи само в пейзажен режим и друг, когато беше в портретен режим. Начинът, по който постигнах това, беше да направя персонализиран „root“ контролер за изглед. След това методът viewWillTransitionToSize за този контролер проверява за ориентация и не анимирано натиска правилния контролер за изглед (така че изглежда като завъртане за потребителя). И след това в Interface Builder задам изрично свойството за ориентация на контролера на изгледа, вместо да бъде изведено. Можете да приложите това решение, като зададете само пейзажна ориентация на контролера за ограничен изглед и след това върху завъртането на портрет, като не правите нищо и деактивирате автоматичното завъртане на контролера за ограничен изглед.

Актуализация

Нямах време да тествам някое от тези, но това са само идеите, които използвах, когато внедрявах моето решение за различен VC за различна ориентация, някаква комбинация от следните се надявам да работи, не мога да бъда 100% сигурен за това, защото направих това преди няколко месеца и не помня точно какво се получи и какво не.

Първо се уверете, че сте настроили ограниченията, както е показано на екранната снимка. Моят има iPad на цял екран и пейзаж, защото това е, което правех, променяйки вашия на каквото ви трябва (портрет и размерът може да се изведе).

View Controller Interface Builder

Сега, преди да направя нещо друго, първо ще проверя дали това е решило проблема. Имах нужда от контролера за изглед на root, защото имах нужда от различен VC за портрет и различен за пейзаж. Трябва само да го ограничите, така че ако това работи, това е перфектно, в противен случай има няколко други неща, които можете да опитате, както е споменато по-долу.

След като това е настроено, първо ще отида до контролера на изгледа, чийто клас искате да ограничите и да предотвратите авторотация, като използвате:

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

Сега, ако направите това, тъй като се ограничавате до портрет, предполагам, че не ви интересува наистина обърнато, така че не е необходимо да правите нищо допълнително. Ако искате да използвате метода viewWillTransitionToSize и да завъртите ръчно.

Ако нещата все още не работят, можете най-накрая да опитате начина на root контролера (но бих използвал това в последния случай). Ето скица от него:

class VC : UIViewController { 
      override func viewDidLoad () { 
           UIDevice.currentDevice().beginGeneratingDeviceOrientationNotifications()
           NSNotificationCenter.defaultCenter().addObserver(self, selector: "orientationChanged:", name: "UIDeviceOrientationDidChangeNotification", object: nil)
         // this gives you access to notifications about rotations
      }
      func orientationChanged(sender: NSNotification)
      {
              // Here check the orientation using this:
              if UIInterfaceOrientationIsLandscape(UIApplication.sharedApplication().statusBarOrientation) { // Landscape }
              if UIInterfaceOrientationIsPortrait(UIApplication.sharedApplication().statusBarOrientation) { // Portrait }
           // Now once only allow the portrait one to go in that conditional part of the view. If you're using a navigation controller push the vc otherwise just use presentViewController:animated:
      }
}

Използвах различните пътища за изразите if, за да прокарам съответно този, който исках, но можете просто да натиснете портретния ръчно и за двата и се надяваме, че един от начините по-горе ще ви помогне.

person Manav Gabhawala    schedule 03.07.2015
comment
Изглежда обещаващо, но трябва да го осмисля. Правилно ли разбирам, че вашето решение води само до пейзажен изглед (което разбира се може да се приложи по същия начин към портретен изглед)? Какво се случва, ако потребителят премине към този изглед, докато устройството е в неподдържана ориентация? Задържа ли се в предишния изглед, докато потребителят не обърне устройството в поддържаната ориентация? - person jerry; 03.07.2015
comment
Не, ако потребителят е в пейзаж, тъй като поддържате само портрет, когато потребителят навигира до този контролер, изгледът ще бъде в портрет и така потребителят ще разбере, че не може да го използва в пейзаж за този бит. Нещо като игри, които поддържат само пейзаж, потребителят осъзнава, че трябва да се завърти в пейзаж, тъй като изгледът не се върти, но във вашия случай се прилага само към част от приложението. - person Manav Gabhawala; 03.07.2015
comment
Не успявам с това, но не съм сигурен дали ви разбрах напълно. Ако времето позволява, можете ли да скицирате накратко кода на контролера за изглед на основния изглед? - person jerry; 03.07.2015
comment
Благодаря за подробното описание. За съжаление не работи. На първо място, действителният изглед се изтласква само когато възникне ротационно събитие, докато контролерът на основния изглед е зареден. След това всяка промяна на ориентацията задейства друг екземпляр на основния (ограничен) изглед, който да бъде избутан в стека, докато контролерът на основния изглед бъде изваден от стека. shouldAutoRotate() изглежда няма ефект. - person jerry; 03.07.2015
comment
За да разрешите проблема с контролера на основния изглед, който първоначално не натиска, просто извикайте функцията orientationChanged в viewDidAppear:animated. Освен това, за да предотвратите многократни натискания, трябва да съхраните текущата ориентация и когато изпълнявате натискането само когато ориентацията се промени, също така забравих да спомена, че трябва да dismiss контролера за изглед или да го отворите в зависимост от това дали използвате UINavigationController. Направете всичко това без анимация, така че потребителят да не го вижда. - person Manav Gabhawala; 03.07.2015
comment
Нека продължим тази дискусия в чата. - person jerry; 03.07.2015