iOS: UIDeviceOrientation is not working as intended

444 views Asked by At

I´ve been using UIDeviceOrientation to check for the physical orientation of the device. The documentation states that this orientation is not dependent on the interface orientation and the generated notifications should fire anyway.

The sample code below works fine on a device that has orientation lock disabled. But it won't work when orientation lock is activated. The sample code prints the UIDeviceOrientation.rawValue every time the device is rotated or shaked.

class ViewController: UIViewController {

    private static var backgroundColors: [UInt: UIColor] = [
        0: .blue, 1: .red, 2: .green, 3: .yellow, 4: .purple, 5: .black, 6: .orange, 7: .white
    ]
    private var colorIndex: UInt = 0
    private var cancelToken: AnyCancellable?

    override func viewDidLoad() {
        super.viewDidLoad()

        UIApplication.shared.applicationSupportsShakeToEdit = true
        // This does not make any difference since UIDevice.current.isGeneratingDeviceOrientationNotifications is always true anyways.
        UIDevice.current.beginGeneratingDeviceOrientationNotifications()

        cancelToken = NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification).sink { _ in
            guard let nextColor = Self.backgroundColors[self.colorIndex % UInt(Self.backgroundColors.keys.count)] else {
                fatalError("Index out of bounds.")
            }
            self.view.backgroundColor = nextColor
            self.colorIndex += 1
            print("Orientation: \(UIDevice.current.orientation.rawValue)")
        }
    }

    deinit {
        UIDevice.current.endGeneratingDeviceOrientationNotifications()
    }

    override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
        guard motion == .motionShake else { return }
        print("Shake -> Orientation: \(UIDevice.current.orientation.rawValue)")
    }

}

As you can see the notification won't be fired when the orientation lock is activated and even the raw value when shaking the device is wrong.

Do I miss something or is this a bug?


Orientation Lock: This means the function from Apples control center to enforce portrait mode for all apps.

1

There are 1 answers

1
matt On

Do I miss something or is this a bug?

It's impossible to say what you know or what you "miss," but this is hardly a bug. From the point of view of the environment in which the app lives, if the orientation lock is on, the device cannot assume a new orientation, so the notification doesn't fire. I would say that this does work as intended, and so the title of the question is wrong (unless, perhaps, you mean it doesn't work as you intended!).

If it's important to you to get past that and learn how the device is physically positioned in space, that is what Core Motion is for. With it, you can detect the direction gravity is coming from relative to the device, which in turn will tell how how the device is oriented in the larger, physical sense.

It's also worth noting that you can't rely on the shake-to-edit feature as a signal, as the user can easily turn it off (it is off on my phone, for example).