web-dev-qa-db-ja.com

向きの変化を検出する方法

Swiftを使用していて、横向きに回転したときにUIViewControllerをロードできるようにしたいのですが、正しい方向を向いている人はいますか?

私はオンラインで何かを見つけることができず、ドキュメントに少し混乱しています。

133
David

これが私がどのように動いたかです:

didFinishLaunchingWithOptions関数内のAppDelegate.Swiftに、次のように入力します。

NotificationCenter.default.addObserver(self, selector: #selector(AppDelegate.rotated), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)

そして、AppDelegateクラスの中に次の関数を追加しました。

func rotated() {
    if UIDeviceOrientationIsLandscape(UIDevice.current.orientation) {
        print("Landscape")
    }

    if UIDeviceOrientationIsPortrait(UIDevice.current.orientation) {
        print("Portrait")
    }

}

これが他の誰かに役立つことを願っています!

ありがとうございます。

178
David
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    if UIDevice.current.orientation.isLandscape {
        print("Landscape")
    if UIDevice.current.orientation.isFlat {
        print("Flat")
    } else {
        print("Portrait")
    }
}
167

AVFoundationでカメラを使用している間に回転を検出する必要があり、didRotateは現在推奨されていない)&willTransitionメソッドは私のニーズには信頼できません。 Davidによって投稿された通知を使用してもうまくいきましたが、Swift 3.x/4.xでは現在のものではありません。

Swift 4.2通知名が変更されました。

クロージャー値はSwift 4.0と同じままです。

var didRotate: (Notification) -> Void = { notification in
        switch UIDevice.current.orientation {
        case .landscapeLeft, .landscapeRight:
            print("landscape")
        case .portrait, .portraitUpsideDown:
            print("Portrait")
        default:
            print("other")
        }
    }

Swift 4.2の通知を設定するには

NotificationCenter.default.addObserver(forName: UIDevice.orientationDidChangeNotification,
                                       object: nil,
                                       queue: .main,
                                       using: didRotate)

Swift 4.2の通知を破棄するには

NotificationCenter.default.removeObserver(self,
                                          name: UIDevice.orientationDidChangeNotification,
                                          object: nil)

非推奨の声明に関して、私の最初のコメントは誤解を招くものだったので、それを更新したいと思いました。すでに述べたように、@objc推論の使用は推奨されていません。これは#selectorを使用するために必要でした。代わりにクロージャを使用することで、これを回避でき、無効なセレクタを呼び出すことによるクラッシュを回避するはずの解決策が得られます。

以下のすべてはXCode 10とiOS 4.2から廃止されました

Swift 4.0Swift 4.0では、Appleは#selectorを使わないように勧めました。そのため、このアプローチでは補完ブロックを使います。このアプローチはSwift 3.xとも後方互換性があり、今後推奨されるアプローチになります。

#selector推論が廃止されたため、@objc関数を使用した場合、これはSwift 4.xプロジェクトで受け取るコンパイラー警告です。

enter image description here

この変更に対するSwift-evolutionのエントリー

コールバックを設定します。

// If you do not use the notification var in your callback, 
// you can safely replace it with _
    var didRotate: (Notification) -> Void = { notification in
        switch UIDevice.current.orientation {
        case .landscapeLeft, .landscapeRight:
            print("landscape")
        case .portrait, .portraitUpsideDown:
            print("Portrait")
        default:
            print("other")
        }
    }

通知を設定します。

NotificationCenter.default.addObserver(forName: .UIDeviceOrientationDidChange,
                                       object: nil,
                                       queue: .main,
                                       using: didRotate)

それを取り壊します:

NotificationCenter.default.removeObserver(self, name: .UIDeviceOrientationDidChange, object: nil)
54
CodeBender

UIDevice-orientationプロパティを使用することは(ほとんどの場合うまくいくとしても)正しくなく、いくつかのバグにつながる可能性があります。例えば、UIDeviceOrientationはデバイスの向きを上向きまたは下向きにした場合、直接の組み合わせはありません。これらの値のUIInterfaceOrientation列挙型。
さらに、アプリを特定の向きに固定した場合、UIDeviceはそれを考慮に入れずに端末の向きを指定します。
一方、iOS8はinterfaceOrientationクラスのUIViewControllerプロパティを非推奨にしました。
インターフェースの向きを検出するために利用可能な2つのオプションがあります。

  • ステータスバーの向きを使う
  • サイズクラスを使用します。iPhoneの場合は、サイズクラスをオーバーライドしないと、現在のインターフェイスの向きを理解する方法がわかります。

まだ欠けているのは、インターフェースの向きの変化の方向を理解する方法です。これはアニメーションの間は非常に重要です。
WWDC 2014「iOS 8でView controller advancement」のセッションで、スピーカーは-will/DidRotateToInterfaceOrientationを置き換える方法を使用して、その問題に対する解決策も提供します。

ここで提案された解決策は部分的に実装されています、より多くの情報 ここ

func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
        let orientation = orientationFromTransform(coordinator.targetTransform())
        let oldOrientation = UIApplication.sharedApplication().statusBarOrientation
        myWillRotateToInterfaceOrientation(orientation,duration: duration)
        coordinator.animateAlongsideTransition({ (ctx) in
            self.myWillAnimateRotationToInterfaceOrientation(orientation,
            duration:duration)
            }) { (ctx) in
                self.myDidAnimateFromInterfaceOrientation(oldOrientation)
        }
    }
17
Andrea

簡単です、これはiOS 8と9/Swift 2/Xcode 7で動作します。ただこのコードをあなたのviewcontroller.Swiftの中に入れるだけです。それはあらゆる向きの変更でスクリーンの寸法を印刷するでしょう、あなたは代わりにあなた自身のコードを置くことができます:

override func didRotateFromInterfaceOrientation(fromInterfaceOrientation: UIInterfaceOrientation) {
        getScreenSize()
    }
    var screenWidth:CGFloat=0
    var screenHeight:CGFloat=0
    func getScreenSize(){
        screenWidth=UIScreen.mainScreen().bounds.width
        screenHeight=UIScreen.mainScreen().bounds.height
        print("SCREEN RESOLUTION: "+screenWidth.description+" x "+screenHeight.description)
    }
11
Josh

私はこの質問がSwiftに対するものであることを知っていますが、それはGoogle検索のトップリンクの1つであり、Objective-Cで同じコードを探しているのであれば:

// add the observer
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(rotated:) name:UIDeviceOrientationDidChangeNotification object:nil];

// remove the observer
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];

// method signature
- (void)rotated:(NSNotification *)notification {
    // do stuff here
}
10
mikeho
9

Swift 3 | UIDeviceOrientationDidChange通知が多すぎることがわかります

次のコードは、縦向きから横向きへの変更に関係なく、デバイスが3D空間で向きを変更するたびに "deviceDidRotate"を印刷します。たとえば、電話機を縦向きにして前後に傾けると、deviceDidRotate()が繰り返し呼び出されます。

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(
        self, 
        selector:  #selector(deviceDidRotate), 
        name: .UIDeviceOrientationDidChange, 
        object: nil
    )
}

func deviceDidRotate() {
    print("deviceDidRotate")
}

これを回避するには、以前のデバイスの向きを保持してdeviceDidRotate()の変更を確認します。

var previousDeviceOrientation: UIDeviceOrientation = UIDevice.current.orientation

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(
        self, 
        selector:  #selector(deviceDidRotate), 
        name: .UIDeviceOrientationDidChange, 
        object: nil
    )
}

func deviceDidRotate() {
    if UIDevice.current.orientation == previousDeviceOrientation { return }
    previousDeviceOrientation = UIDevice.current.orientation
    print("deviceDidRotate")
}

または、デバイスが横長から縦長に変化したときにのみ呼び出される別の通知を使用することもできます。この場合はUIApplicationDidChangeStatusBarOrientation通知を使いたいでしょう。

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(
        self, 
        selector:  #selector(deviceDidRotate), 
        name: .UIApplicationDidChangeStatusBarOrientation, 
        object: nil
    )
}

func deviceDidRotate() {
    print("deviceDidRotate")
}
8
Derek Soike

目的Cでは

-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator

スウィフトで

func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)

このメソッドをオーバーライドして方向の変化を検出します。

7
Mahendra
override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) {
    //Swift 3
    getScreenSize()
}


func getScreenSize(){
   let screenWidth = UIScreen.main.bounds.width
   let  screenHeight = UIScreen.main.bounds.height
    print("SCREEN RESOLUTION: \(screenWidth.description) x \(screenHeight.description)")
}
5
Jeet Gandhi

Swift 3.0で向きの変化を検出する方法の完全に実用的な実装

face upface downの電話の向きは私にとって重要であるため、この実装を使用することを選択しました。また、向きが指定の位置にあることがわかったときにのみビューを変更することを望みました。

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        //1
        NotificationCenter.default.addObserver(self, selector: #selector(deviceOrientationDidChange), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)

    }

    deinit {
        //3
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
    }

    func deviceOrientationDidChange() {
        //2
        switch UIDevice.current.orientation {
        case .faceDown:
            print("Face down")
        case .faceUp:
            print("Face up")
        case .unknown:
            print("Unknown")
        case .landscapeLeft:
            print("Landscape left")
        case .landscapeRight:
            print("Landscape right")
        case .portrait:
            print("Portrait")
        case .portraitUpsideDown:
            print("Portrait upside down")
        }
    }

}

注意すべき重要な点は以下のとおりです。

  1. DeviceOrientationDidChange通知ストリームを監視して、それを関数deviceOrientationDidChangeに結び付けます。
  2. 次に、デバイスの向きをオンにします。必ずunknownの向きがあることに注意してください。
  3. 他の通知と同様に、viewControllerが初期化解除される前に、通知ストリームの監視を停止するようにしてください。

誰かがこれが役に立つことを願っています。

5
Rob Norback

これは、デバイスの向きを検出する簡単な方法です。(Swift

override func willRotate(to toInterfaceOrientation: UIInterfaceOrientation, duration: TimeInterval) {
            handleViewRotaion(orientation: toInterfaceOrientation)
        }

    //MARK: - Rotation controls
    func handleViewRotaion(orientation:UIInterfaceOrientation) -> Void {
        switch orientation {
        case .portrait :
            print("portrait view")
            break
        case .portraitUpsideDown :
            print("portraitUpsideDown view")
            break
        case .landscapeLeft :
            print("landscapeLeft view")
            break
        case .landscapeRight :
            print("landscapeRight view")
            break
        case .unknown :
            break
        }
    }
4
Ram Madhavan

回転が変更されたかどうかを確認します。viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)

coordinator.animateAlongsideTransition(nil) { (UIViewControllerTransitionCoordinatorContext)を使えば、遷移が終了したかどうかを確認できます。

以下のコードを参照してください。

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {

    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)

    coordinator.animateAlongsideTransition(nil) { (UIViewControllerTransitionCoordinatorContext) in
        // if you want to execute code after transition finished
        print("Transition finished")
    }

    if size.height < size.width {
        // Landscape
        print("Landscape")
    } else {
        // Portrait
        print("Portrait")
    }

}
4
SDW

回転が完了した後に何かをしたい場合は、次のようなUIViewControllerTransitionCoordinator完了ハンドラを使用できます。

public override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)

    // Hook in to the rotation animation completion handler
    coordinator.animate(alongsideTransition: nil) { (_) in
        // Updates to your UI...
        self.tableView.reloadData()
    }
}
4
David Pettigrew

あなたはどのクラスにもこの機能を追加できるので、私はオリエンテーション通知をチェックするのが好きです。ビューやビューコントローラである必要はありません。アプリの代理人でも。

Swift 5:

    //ask the system to start notifying when interface change
    UIDevice.current.beginGeneratingDeviceOrientationNotifications()
    //add the observer
    NotificationCenter.default.addObserver(
        self,
        selector: #selector(orientationChanged(notification:)),
        name: UIDevice.orientationDidChangeNotification,
        object: nil)

通知をキャッシュするより

    @objc func orientationChanged(notification : NSNotification) {
        //your code there
    }
3

IOS 8以降、これは正しい方法です。

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)

    coordinator.animate(alongsideTransition: { context in
        // This is called during the animation
    }, completion: { context in
        // This is called after the rotation is finished. Equal to deprecated `didRotate`
    })
}
3
PatrickDotStar

私のアプローチは上記のような bpedit に似ていますが、iOS 9+に焦点を当てています。ビューが回転したときに FSCalendar の範囲を変更したいと思いました。

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)

    coordinator.animateAlongsideTransition({ (context) in
        if size.height < size.width {
            self.calendar.setScope(.Week, animated: true)
            self.calendar.appearance.cellShape = .Rectangle
        }
        else {
            self.calendar.appearance.cellShape = .Circle
            self.calendar.setScope(.Month, animated: true)

        }

        }, completion: nil)
}

これはうまくいきましたが、私はそれについて愚かな気がしました:)

coordinator.animateAlongsideTransition({ (context) in
        if size.height < size.width {
            self.calendar.scope = .Week
            self.calendar.appearance.cellShape = .Rectangle
        }
        }) { (context) in
            if size.height > size.width {
                self.calendar.scope = .Month
                self.calendar.appearance.cellShape = .Circle
            }
    }
2

私はUIUserInterfaceSizeClassを使ってUIViewControllerクラスの方向の変化を検出します。

override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) {

    let isiPadLandscapePortrait = newCollection.horizontalSizeClass == .regular && newCollection.verticalSizeClass == .regular
    let isiPhonePlustLandscape = newCollection.horizontalSizeClass == .regular && newCollection.verticalSizeClass == .compact
    let isiPhonePortrait = newCollection.horizontalSizeClass == .compact && newCollection.verticalSizeClass == .regular
    let isiPhoneLandscape = newCollection.horizontalSizeClass == .compact && newCollection.verticalSizeClass == .compact

     if isiPhonePortrait {
         // do something...
     }
}
2
pableiros

Swift 4:

override func viewWillAppear(_ animated: Bool) {
    NotificationCenter.default.addObserver(self, selector: #selector(deviceRotated), name: UIDevice.orientationDidChangeNotification, object: nil)
}

override func viewWillDisappear(_ animated: Bool) {
    NotificationCenter.default.removeObserver(self, name: UIDevice.orientationDidChangeNotification, object: nil)
}

@objc func deviceRotated(){
    if UIDevice.current.orientation.isLandscape {
        //Code here
    } else {
        //Code here
    }
}

さまざまなView Controllerにわたって検出する必要がある場合、多くの回答が役に立ちません。これはうまくいきます。

2
Joel

Swift 3の場合

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    if UIDevice.current.orientation.isLandscape {
        //Landscape
    }
    else if UIDevice.current.orientation.isFlat {
        //isFlat
    }
    else {
        //Portrait
    }
}
1
Mamta
- (void)viewDidLoad {
  [super viewDidLoad];
  [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(OrientationDidChange:) name:UIDeviceOrientationDidChangeNotification object:nil];
}

-(void)OrientationDidChange:(NSNotification*)notification {
  UIDeviceOrientation Orientation=[[UIDevice currentDevice]orientation];

  if(Orientation==UIDeviceOrientationLandscapeLeft || Orientation==UIDeviceOrientationLandscapeRight) {
    NSLog(@"Landscape");
  } else if(Orientation==UIDeviceOrientationPortrait) {
    NSLog(@"Potrait Mode");
  }
}

注:UIViewControllerがどちらの方向にあるかを識別するためにこのコードを使用してください。

0
Mannam Brahmam