I use UISplitViewController
. I wanted to display an empty selection detail scene when the user rotates his iPhone 6 Plus into portrait and doesn't see any detail anymore. (All other devices behave predictably. Only the 6 Plus can change its appearance.) I now use a split view delegate instead which involves kind of weird queries, but that's not the point.
I wondered how to find out if the iPhone 6 rotated into landscape.
The best idea I came up with: react to trait environment changes. The master view controller stays compact at all times, only it's parent navigation view controller changes from compact to regular and back again. (And UIWindow, too, of course.)
When using a split view controller, for subclasses of UINavigationController
in the "Master", traitCollectionDidChange:
will be called twice when using an iPhone 6 Plus and rotating into landscape. It is called once when rotating back.
willTransitionToTraitCollection:withTransitionCoordinator:
is even called three times and 1 time, respectively.
I imagine that's because in landscape you can see two view controllers alongside each other. It doesn't make sense to me that the UINavigationController
receives the calls for sub view controllers at all, though.
Since UITraitCollections
don't contain information about which view controller is affected, I cannot determine if the environment changed from regular to compact horizontal size reliably. One of the trait collections will report the correct new value, but I cannot discern them from one another.
How'd you solve this, now that the callbacks are called multiple times with different values?
I know it is an old thread but I couldn't find the solution for the same problem online so here's my two cents.
The UISplitViewController is a container view controller. So it is considered "displayed" even if there are view controllers on top of it. In the apple documentation it says that:
"View controllers forward the trait change message to their child view controllers. Presentation controllers forward the trait change to their presented view controller."
Hence whenever you introduce a change in the size class of the split view controller it calls it's delegate and the delegates of both its children.
For more info check: https://developer.apple.com/reference/uikit/uicontentcontainer/1621511-willtransitiontotraitcollection
Edit: I just noticed that I did not explain fully why the UISplitViewController gets called thrice. If the willTransitionToTraitCollection:withTransitionCoordinator: is not implemented in the presented views it probably follows the convention which Apple sets for it:
"If you override this method in your own objects, always call super at some point in your implementation so that UIKit can forward the trait changes to the associated presentation controller and to any child view controllers."
The idea behind it I think is that on a change in the traitCollection of a child view controller you might want to change the layout and/or number of its siblings. For that purpose any change in the child controllers must call the container so it knows what's up and adjust accordingly. However it cannot track which change overlaps the others so all get registered.
My solution was to handle the change in the child view controllers(UINavigationControllers in my case) instead of the splitViewController by subclassing them and adding the transition logic.