Каков "правильный" способ обработки изменений ориентации в iOS 8? - программирование
Подтвердить что ты не робот

Каков "правильный" способ обработки изменений ориентации в 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
4b9b3361

Ответ 1

Apple рекомендует использовать классы размера в качестве грубой меры, насколько доступно пространство на экране, так что ваш пользовательский интерфейс может значительно изменить его макет и внешний вид. Учтите, что iPad на портрете имеет такие же классы размеров, как и в ландшафте (Regular width, Regular height). Это означает, что ваш пользовательский интерфейс должен быть более или менее схожим между двумя ориентациями.

Однако изменение от портрета к пейзажу в 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:]

    }];
}

Отлично! Теперь вы получаете обратные вызовы прямо перед началом вращения, и после этого заканчивается. Но как насчет фактического знания, является ли ротация портрета или пейзажа?

Apple рекомендует думать о ротации как о простом изменении размера родительского представления. Другими словами, во время поворота iPad от портрета к пейзажу вы можете думать о нем как об уровне корневого уровня, просто меняя его bounds.size от {768, 1024} до {1024, 768}. Зная это, вы должны использовать size, переданный в метод viewWillTransitionToSize:withTransitionCoordinator: выше, чтобы выяснить, поворачиваетесь ли вы на портретный или альбомный.

Если вы хотите еще более простой способ перенести устаревший код на новый способ работы с iOS 8, подумайте об использовании этой простой категории в UIView, что может быть используется для определения того, является ли представление "портретным" или "ландшафтным" в зависимости от его размера.

Повторить:

  • Вы должны использовать классы размера, чтобы определить, когда показывать принципиально разные пользовательские интерфейсы (например, пользовательский интерфейс, похожий на iPhone, в сравнении с пользовательским интерфейсом, подобным iPad).
  • Если вам нужно внести небольшие корректировки в пользовательский интерфейс, если классы размера не изменяются, но размер вашего контейнера (родительский вид), например, когда iPad вращается, используйте обратный вызов viewWillTransitionToSize:withTransitionCoordinator: в UIViewController.
  • Каждое представление в вашем приложении должно принимать только решения макета на основе пространства, в котором оно было предоставлено макету. Пусть естественная иерархия представлений каскадирует эту информацию.
  • Аналогично, не используйте statusBarOrientation - это в основном свойство уровня устройства, чтобы определить, следует ли компоновать представление для "портрета" и "пейзаж". Ориентация строки состояния должна использоваться только кодом, касающимся таких вещей, как UIWindow, которые фактически живут на самом корневом уровне приложения.

Ответ 2

На основе smileyborg очень хорошо подробный (и принятый) ответ, вот адаптация с помощью быстрого 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
}

Ответ 3

Я просто использую Центр уведомлений:

Добавить переменную ориентации (объяснит в конце)

//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 вызывает только код, если он переключился на противоположную ориентацию.

Ответ 4

С точки зрения пользовательского интерфейса, я считаю, что использование классов классов - это рекомендуемый 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/

ИЗМЕНИТЬ Обновлено Ссылка: https://carpeaqua.com/2014/06/14/thinking-in-terms-of-ios-8-size-classes/ (Кредит: Koen)