web-dev-qa-db-ja.com

iOS 8で方向の変更を処理する「正しい」方法は何ですか?

誰かがiOS 8でポートレートとランドスケープのインターフェイスの向きを操作するための「正しい」または「最良の」アプローチを教えてもらえますか?その目的で使用したいすべての機能はiOS 8で非推奨になったようで、私の研究では明確でエレガントな代替手段は見つかりませんでした。私たちがポートレートモードかランドスケープモードかを判断するために、実際に幅と高さを調べることになっていますか?

たとえば、View Controllerでは、次の擬似コードをどのように実装する必要がありますか?

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
99
rmp251

Appleは、UIがレイアウトと外観を大幅に変更できるように、使用可能な画面スペースの大まかな尺度としてサイズクラスを使用することをお勧めします。縦向きのiPadには、横向きのiPadと同じサイズクラス(通常の幅、通常の高さ)があることを考慮してください。これは、2つの方向のUIが多少似ていることを意味します。

ただし、iPadでポートレートからランドスケープへの変更は十分に重要であるため、サイズクラスは変更されていませんが、UIを少し調整する必要があります。 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}に変更するだけと考えることができます。これを知っているので、上のviewWillTransitionToSize:withTransitionCoordinator:メソッドに渡されたsizeを使用して、ポートレートまたはランドスケープのどちらに回転しているかを判断する必要があります。

従来のコードを新しいiOS 8の方法にさらにシームレスに移行する方法が必要な場合は、UIViewで this simple category を使用することを検討してください。これは、ビューが「ポートレート」かどうかを判断するために使用できますまたはそのサイズに基づいた「風景」。

要点をまとめると:

  1. サイズクラスを使用して、根本的に異なるUIを表示するタイミングを決定する必要があります(「iPhoneに似た」UIと「iPadに似た」UI)
  2. サイズクラスを変更しないでUIを少し調整する必要があるが、iPad(iPad回転するには、UIViewControllerでviewWillTransitionToSize:withTransitionCoordinator:コールバックを使用します。
  3. アプリのすべてのビューは、レイアウトに割り当てられたスペースに基づいてレイアウトを決定するだけです。ビューの自然な階層がこの情報をカスケードします。
  4. 同様に、statusBarOrientation(基本的にデバイスレベルのプロパティ)を使用して、「ポートレート」と「ランドスケープ」のビューをレイアウトするかどうかを決定しないでください。ステータスバーの方向は、アプリのまさにルートレベルに実際に存在するUIWindowのようなものを処理するコードでのみ使用する必要があります。
251
smileyborg

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
}
15
CMont

私は単に通知センターを使用します:

方向変数を追加します(最後に説明します)

//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ステートメントを追加すると、反対方向に切り替わった場合にのみコードが呼び出されます。

11
inVINCEable

UIの観点から、サイズクラスを使用することは、さまざまな向き、サイズ、スケールのインターフェイスを処理するためのAppleの推奨アプローチであると考えています。

セクションを参照してください:Traits Describe Desize Size Class and Scale of the Interfacehere: 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)

2
Aaron