Why is viewWillTransitionToSize... not called when displayModeButtonItem triggers splitViewController collapse?

4k views Asked by At

I have a UISplitViewController whose secondary (detail) VC is a UICollectionViewController. I want the cells of the collection to resize based on changes to the size and aspect of the collection view. I trigger this resizing by overriding the UIContentContainer protocol method:

// MARK: - UIContentContainer protocol methods

override
func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
{
    setFlowLayoutItemSizeForViewSize(size)
    collectionViewLayout.invalidateLayout()
}

This is called and works just how I want when the device rotates; but this method is not being called when the button supplied by splitViewController?.displayModeButtonItem() is pressed to show or collapse the primary (master) view controller. Since that collapse necessarily changes the size of the secondary (detail) view, I would have though that the viewWillTransitionToSize... method should be called when it is triggered.

So, two questions:

1) Should the viewWillTransitionToSize... method in fact be invoked when the displayModeButtonItem is pressed? If so, I seem to have found a bug.

2) If what I'm seeing is in fact the correct behavior, can anyone suggest a way for my secondary (detail) controller to "know" either when the displayModeButtonItem is pressed, or when its size is changing as a result of that button being pressed?

Thanks!

Carl

3

There are 3 answers

4
kadam On BEST ANSWER

1) Not a bug; displayModeChange is not being treated a sizeTransition

2) Your UISplitviewController most likely already has a UISplitViewControllerDelegate which can implement the optional:

splitViewController(_ svc: UISplitViewController,
      willChangeToDisplayMode displayMode: UISplitViewControllerDisplayMode)

method that will get called with UISplitViewControllerDisplayModePrimaryHidden or UISplitViewControllerDisplayModeAllVisible depending on which mode the splitView is switching to.

0
malhal On

There is a built-in notification for this:

// Sometimes view controllers that are using showViewController:sender and showDetailViewController:sender: will need to know when the split view controller environment above it has changed. This notification will be posted when that happens (for example, when a split view controller is collapsing or expanding). The NSNotification's object will be the view controller that caused the change.
UIKIT_EXTERN NSNotificationName const UIViewControllerShowDetailTargetDidChangeNotification NS_AVAILABLE_IOS(8_0);

See Apple's AdaptivePhotos sample for how to use it.

1
Bacon On

The way I solved this problem was to subclass the UISplitViewController and overriding the viewWillTransitionToSize(...) as followed:

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

    //Get the master controller
    guard let masterController = viewControllers[0] as? UIViewController else {
        return print("master controller not of type UINavigationController")
    }

    //Notify masterController that the view will transition
    masterController.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
}

Hope it helps!