简体   繁体   中英

Reacting to orientation changes without .faceUp and .faceDown

I have a UIView that appears/disappears with an animation when the device is in portrait/landscape mode.

I am doing it like this:

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

func deviceOrientationChanged() {
        switch UIDevice.current.orientation {
        case .portrait:
            //appear
        case .landscapeLeft, .landscapeRight:
            //disappear
        case default: 
            //appear; here lies the problem
        }
    }

The issue are .faceDown and .faceUp . I want to ignore the orientation changes to these orientation and have nothing change. Putting them in the default: of the switch results in uneccessarily repeated animations when the device is put back into portrait.

I am sure I could hack together a solution. But I find the simplicity of the problem frustrating.

Is there a property that only informs about changes to .portrait , .landscapeRight , .landscapeLeft and .portraitUpsideDown ?

Yes interfaceOrientation has been deprecated, now you should use statusBarOrientation or traits and related methods to detect the current orientation or the changes in orientation.
I'd like to point you to this post , device orientation will not consider the eventual orientation lock that the user can set in the options.
While statusBarOrientation seems to be deprecated is apparently only on the setter as stated here from an Apple employee.

How could you present a landscape view controller in a portrait application? this is just one of the possible example:

// ApplicationDelegate overridden method
    func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        if topController() is FullGraphViewController {
            return .all
        }  else {
            return .portrait
        }
    }

Basically I say that when a FullGraphViewController is presented it can be displayed in all possible orientations.

// FullgraphViewController overridden methods
    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        if landActive {
            return [UIInterfaceOrientationMask.allButUpsideDown]
        }
        return [UIInterfaceOrientationMask.portrait]
    }

    override var shouldAutorotate: Bool {
        return true
    }

    override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
        return .portrait
    }

Here I'm saying that view should be presented in portrait this will lead to a nice orientation animation, the view can rotate and if landscape flag is active it can rotate in all orientation except upside-down.
To intercept orientation changes you can:

  • Use device orientation changes, but only to trigger the presentation of the landscape view controller
  • Use the traits variation callback to trigger the presentation, but your app is like mine and you have pick only portrait orientation in general settings you will not receive any of those call callbacks

Inside the orientation changes callback from the vc where you want to present the landscape interface, you can present your landscape view controller:

func orientationChanged(_ notification: Notification) {
    let orientation = UIDevice.current.orientation
    if UIDeviceOrientationIsValidInterfaceOrientation(orientation) && UIDeviceOrientationIsLandscape(orientation) {
        let vc = storyboard!.instantiateViewController(withIdentifier: Constants.ViewControllerIdentifiers.LandscapeFullGraphViewController) as! FullGraphViewController
        vc.title = navigatorViewController?.navigationBarView.barTitle
        vc.instrumentInfo = instrumentInfo
        vc.modalTransitionStyle = .crossDissolve
        present(vc, animated: true) {
            vc.landActive = true
        }
    }
}

The landActive is a property of the FullGraphViewController that when is set asks the rotation from port to landscape to begin.

var landActive = true {
        didSet(old) {
            UIViewController.attemptRotationToDeviceOrientation()
            view.setNeedsLayout()
            view.layoutIfNeeded()
        }
    }


Please note the function UIDeviceOrientationIsValidInterfaceOrientation , that is very important and discharges faceup and facedown.

Use self.view.window?.windowScene?.interfaceOrientation .

This value will be either portrait , portraitUpsideDown , landscapeRight , or landscapeLeft .

See here for documentation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM