Каков "правильный" способ обработки изменений ориентации в iOS 8?
может ли кто-нибудь сказать мне "правильный" или "лучший" подход к работе с портретной и альбомной ориентацией интерфейса в iOS 8? Похоже, что все функции, которые я хочу использовать для этой цели, устарели в iOS 8, и мои исследования не нашли четкой, элегантной альтернативы. Я действительно должен смотреть на ширину и высоту, чтобы определить для себя, находимся ли мы в портретном или ландшафтном режиме?
например, в моем контроллере представления, как я должен реализовать следующее псевдокод?
if we are rotating from portrait to landscape then
do portrait things
else if we are rotating from landscape to portrait then
do landscape things
4 ответа:
Apple рекомендует использовать классы размеров в качестве грубой меры того, сколько места на экране доступно, чтобы ваш пользовательский интерфейс мог значительно изменить его макет и внешний вид. Учтите, что iPad в портрете имеет те же классы размеров, что и в альбомной ориентации (обычная ширина, обычная высота). Это означает, что ваш пользовательский интерфейс должен быть более или менее похож между двумя ориентациями.
тем не менее, изменение от портрета к пейзажу в iPad является достаточно значительным, что вам может потребоваться внесите некоторые небольшие изменения в пользовательский интерфейс, даже если классы размера не изменились. Поскольку методы, связанные с ориентацией интерфейса на
UIViewController
были устарели, Apple теперь рекомендует реализовать следующий новый метод вUIViewController
замена:- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator { [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; // Code here will execute before the rotation begins. // Equivalent to placing it in the deprecated method -[willRotateToInterfaceOrientation:duration:] [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) { // Place code here to perform animations during the rotation. // You can pass nil or leave this block empty if not necessary. } completion:^(id<UIViewControllerTransitionCoordinatorContext> context) { // Code here will execute after the rotation has finished. // Equivalent to placing it in the deprecated method -[didRotateFromInterfaceOrientation:] }]; }
великолепно! Теперь вы получаете обратные вызовы прямо перед началом вращения и после его завершения. Но как насчет того, чтобы на самом деле знать, является ли вращение портретом или пейзажем?
Яблоко рекомендует думать о вращении как о простом изменении размера родительского представления. Другими словами, во время поворота iPad от портрета к ландшафту вы можете думать об этом как о представлении корневого уровня, просто меняя его
bounds.size
С{768, 1024}
до{1024, 768}
. Зная это, вы должны использоватьsize
перешел вviewWillTransitionToSize:withTransitionCoordinator:
метод выше, чтобы выяснить, вращается ли вы к портретной или альбомной ориентации.если вы хотите еще более простой способ переноса устаревшего кода в новую iOS 8 способ делать вещи, рассмотреть возможность использования это простая категория на UIView, который можно использовать для определения того, является ли вид "портретом" или "пейзажем" на основе его размера.
подведем итог:
- вы должны использовать классы размера, чтобы определить, когда показывать принципиально разные UI (например, "iPhone-подобный" UI против "iPad-подобного" UI)
- Если вам нужно внести небольшие изменения в свой пользовательский интерфейс, когда размер классов не изменить, но ваш контейнер (Родительский вид) размер делает, например, когда iPad вращается, используйте
viewWillTransitionToSize:withTransitionCoordinator:
обратный вызов в UIViewController.- каждый вид в вашем приложении должен принимать решения о макете только на основе пространства, в котором он был предоставлен макету. Пусть естественная иерархия представлений каскадирует эту информацию вниз.
- точно так же, не используйте
statusBarOrientation
-- который в основном является свойством уровня устройства -- чтобы определить, нужно ли компоновать представление для "портрета" против "ландшафта". Строка состояния ориентация должна использоваться только кодом, имеющим дело с такими вещами, какUIWindow
которые на самом деле живут на самом корневом уровне приложения.
на основе очень хорошо детализированного (и принятого) ответа smileyborg, вот адаптация с использованием swift 3:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) coordinator.animate(alongsideTransition: nil, completion: { _ in self.collectionView.collectionViewLayout.invalidateLayout() }) }
и
UICollectionViewDelegateFlowLayout
реализацииpublic func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { // retrieve the updated bounds let itemWidth = collectionView.bounds.width let itemHeight = collectionView.bounds.height // do whatever you need to do to adapt to the new size }
Я просто использую Центр уведомлений:
добавить переменную ориентации (объясню в конце)
//Above viewdidload var orientations:UIInterfaceOrientation = UIApplication.sharedApplication().statusBarOrientation
добавить уведомление, когда появляется вид
override func viewDidAppear(animated: Bool) { NSNotificationCenter.defaultCenter().addObserver(self, selector: "orientationChanged:", name: UIDeviceOrientationDidChangeNotification, object: nil) }
удалить уведомление, когда взгляд уходит
override func viewWillDisappear(animated: Bool) { NSNotificationCenter.defaultCenter().removeObserver(self, name: UIDeviceOrientationDidChangeNotification, object: nil) }
получает текущую ориентацию при срабатывании уведомления
func orientationChanged (notification: NSNotification) { adjustViewsForOrientation(UIApplication.sharedApplication().statusBarOrientation) }
проверяет ориентацию (книжная / альбомная) и ручки события
func adjustViewsForOrientation(orientation: UIInterfaceOrientation) { if (orientation == UIInterfaceOrientation.Portrait || orientation == UIInterfaceOrientation.PortraitUpsideDown) { if(orientation != orientations) { println("Portrait") //Do Rotation stuff here orientations = orientation } } else if (orientation == UIInterfaceOrientation.LandscapeLeft || orientation == UIInterfaceOrientation.LandscapeRight) { if(orientation != orientations) { println("Landscape") //Do Rotation stuff here orientations = orientation } } }
причина, по которой я добавляю переменную ориентации, заключается в том, что при тестировании на физическом устройстве уведомление об ориентации вызывается при каждом незначительном движении в устройстве, а не только при его вращении. Добавление операторов var и if вызывает код только в том случае, если он переключился на противоположную ориентацию.
с точки зрения пользовательского интерфейса, я считаю, что использование классов размеров является рекомендуемым подходом Apple для обработки интерфейсов в разных ориентациях, размерах и масштабах.
раздел: черты описывают класс размера и масштаб интерфейса здесь: https://developer.apple.com/library/ios/releasenotes/General/WhatsNewIniOS/Articles/iOS8.html
"iOS 8 добавляет новые функции, которые позволяют работать с размером экрана и ориентацией гораздо более универсальный."
Это одна хорошая статья, Как хорошо: https://carpeaqua.com/thinking-in-terms-of-ios-8-size-classes/
EDIT Обновленная Ссылка: https://carpeaqua.com/2014/06/14/thinking-in-terms-of-ios-8-size-classes/ (кредит: Koen)