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


104

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

3
のドキュメントをご覧くださいUIViewController。ビューRotations`の取り扱い」の項を参照してくださいそれはあなたが何をすべきかを説明します。。
rmaddy

それらが非推奨であることは手がかりです。何か他のものを使用する必要があります...何か他のものはAutoLayoutとサイズクラスである必要があります:-)
アーロン

回答:


262

Appleは、UIがそのレイアウトと外観を大幅に変更できるように、利用可能な画面スペースの大まかな目安としてサイズクラスを使用することを推奨しています。縦向きのiPadは横向きと同じサイズのクラス(通常の幅、通常の高さ)を持っていると考えてください。つまり、UIは2つの方向間でほぼ同じである必要があります。

ただし、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}。これを知っているので、上記sizeviewWillTransitionToSize:withTransitionCoordinator:メソッドに渡されたものを使用して、ポートレートに回転しているかランドスケープに回転しているかを判断する必要があります。

レガシーコードを新しいiOS 8の方法に移行するさらにシームレスな方法が必要な場合は、UIViewでこの単純なカテゴリを使用することを検討してください。これを使用して、ビューがサイズ。

要点をまとめると:

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

5
正解です。ところで、ALのあなたのYouTubeビデオは非常に有益でした。共有してくれてありがとう。見てみな!youtube.com/watch?v=taWaW2GzfCI
smileBot 2015

2
私が見つけた唯一の問題は、デバイスの向きを知りたいことが時々あり、これはあなたにそれを知らせないことです。iPadでは、ステータスバーまたはデバイスの向きの値が変更される前に呼び出されます。ユーザーがデバイスを縦向きにしているか、逆向きにしているかはわかりません。モックUIViewControllerTransitionCoordinatorは悪夢なので、テストすることも不可能です:-(
Darrarski

@Darrarskiこれらの問題に対処するためのエレガントなソリューションを見つけましたか?
Xvolks 2017年

では、どこにいるのviewdidlayoutsubviewsですか?viewdidlayoutsubviews回転によるバウンドの変化をキャプチャするために使用されると思いました。それについて詳しく説明してもらえますか?
ハニー

1
statusbarorientationを使用しない場合、左のランドスケープと右のランドスケープを区別するにはどうすればよいですか?その区別が必要です。-また、ここに述べたような他の問題があるstackoverflow.com/questions/53364498/...は
ディーパックシャルマ

17

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
}

11

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

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

//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
これは、アプリのすべてのビューが、与えられたスペースを考慮するのではなく、デバイスの向きに基づいて表示方法を決定することを意味するため、Appleの推奨されるアプローチではありません。
スマイリーボー2014

2
Appleはまた、8.0ではハードウェアを考慮していません。AVPreviewレイヤーに、ビューコントローラー上に表示される場合は向きを気にする必要がないことを伝えます。機能しませんが、8.2で修正されています
Nick Turner

superviewDidAppearviewWillDisappear呼ばれるべき
アンドリューBogaevskyi

注:UIDeviceOrientation!= UIInterfaceOrientation。私の実験では、statusBarOrientationは信頼できません。
nnrales

2

UIの観点からは、サイズクラスを使用することは、さまざまな方向、サイズ、スケールでインターフェイスを処理するために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)


ええ、彼のサイト全体が現在ダウンしているようです。
アーロン

記事は確かに読む価値があり、ここに正しいアドレスがあります:carpeaqua.com/thinking-in-terms-of-ios-8-size-classes
uem

しかし、サイズクラスやUIについてではなく、たとえばAVFoundationについて話している場合はどうでしょう。ビデオを録画するとき、正しいメタデータを設定するために、viewControllersの向きを知っている必要がある場合があります。これは簡単に不可能です。「多用途」。
Julian F. Weinert、

それはOPが尋ねたり話したりしていたことではありません。
Aaron、

1
更新されたリンク:carpeaqua.com/2014/06/14/...
公園
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.