Swift - How to detect orientation changes

后端 未结 13 1766
余生分开走
余生分开走 2020-11-29 19:49

I want to add two images to single image view (i.e for landscape one image and for portrait another image)but i don\'t know how to detect orientation changes using swift lan

相关标签:
13条回答
  • 2020-11-29 20:42

    To get the correct orientation on app start you have to check it in viewDidLayoutSubviews(). Other methods described here won't work.

    Here's an example how to do it:

    var mFirstStart = true
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        if (mFirstStart) {
            mFirstStart = false
            detectOrientation()
        }
    }
    
    func detectOrientation() {
        if UIDevice.current.orientation.isLandscape {
            print("Landscape")
            // do your stuff here for landscape
        } else {
            print("Portrait")
            // do your stuff here for portrait
        }
    }
    
    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        detectOrientation()
    }
    

    This will work always, on app first start, and if rotating while the app is running.

    0 讨论(0)
  • 2020-11-29 20:46

    Swift 3 Above code updated:

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)
    
        if UIDevice.current.orientation.isLandscape {
            print("Landscape")
        } else {
            print("Portrait")
        }
    }
    
    0 讨论(0)
  • 2020-11-29 20:47

    You can use viewWillTransition(to:with:) and tap into animate(alongsideTransition:completion:) to get the interface orientation AFTER the transition is complete. You just have to define and implement a protocol similar to this in order to tap into the event. Note that this code was used for a SpriteKit game and your specific implementation may differ.

    protocol CanReceiveTransitionEvents {
        func viewWillTransition(to size: CGSize)
        func interfaceOrientationChanged(to orientation: UIInterfaceOrientation)
    }
    
    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
            super.viewWillTransition(to: size, with: coordinator)
    
            guard
                let skView = self.view as? SKView,
                let canReceiveRotationEvents = skView.scene as? CanReceiveTransitionEvents else { return }
    
            coordinator.animate(alongsideTransition: nil) { _ in
                if let interfaceOrientation = UIApplication.shared.windows.first?.windowScene?.interfaceOrientation {
                    canReceiveRotationEvents.interfaceOrientationChanged(to: interfaceOrientation)
                }
            }
    
            canReceiveRotationEvents.viewWillTransition(to: size)
        }
    

    You can set breakpoints in these functions and observe that interfaceOrientationChanged(to orientation: UIInterfaceOrientation) is always called after viewWillTransition(to size: CGSize) with the updated orientation.

    0 讨论(0)
  • 2020-11-29 20:48

    All previous contributes are fine, but a little note:

    a) if orientation is set in plist, only portrait or example, You will be not notified via viewWillTransition

    b) if we anyway need to know if user has rotated device, (for example a game or similar..) we can only use:

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

    tested on Xcode8, iOS11

    0 讨论(0)
  • 2020-11-29 20:52

    Swift 4.2, RxSwift

    If we need to reload collectionView.

    NotificationCenter.default.rx.notification(UIDevice.orientationDidChangeNotification)
        .observeOn(MainScheduler.instance)
        .map { _ in }            
        .bind(to: collectionView.rx.reloadData)
        .disposed(by: bag)
    

    Swift 4, RxSwift

    If we need to reload collectionView.

    NotificationCenter.default.rx.notification(NSNotification.Name.UIDeviceOrientationDidChange)
        .observeOn(MainScheduler.instance)
        .map { _ in }            
        .bind(to: collectionView.rx.reloadData)
        .disposed(by: bag)
    
    0 讨论(0)
  • 2020-11-29 20:53

    Swift 4

    I've had some minor issues when updating the ViewControllers view using UIDevice.current.orientation, such as updating constraints of tableview cells during rotation or animation of subviews.

    Instead of the above methods I am currently comparing the transition size to the view controllers view size. This seems like the proper way to go since one has access to both at this point in code:

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)
        print("Will Transition to size \(size) from super view size \(self.view.frame.size)")
    
        if (size.width > self.view.frame.size.width) {
            print("Landscape")
        } else {
            print("Portrait")
        }
    
        if (size.width != self.view.frame.size.width) {
            // Reload TableView to update cell's constraints.
        // Ensuring no dequeued cells have old constraints.
            DispatchQueue.main.async {
                self.tableView.reloadData()
            }
        }
    
    
    }
    

    Output on a iPhone 6:

    Will Transition to size (667.0, 375.0) from super view size (375.0, 667.0) 
    Will Transition to size (375.0, 667.0) from super view size (667.0, 375.0)
    
    0 讨论(0)
提交回复
热议问题