skip to Main Content

I’m trying to update the constraints and change the layout of my subviews when the user rotates their device.

From what I understand, both viewDidLayoutSubviews() and traitCollectionDidChange() are able to respond to changes in the interface orientation (e.g. when the device is rotated).

According to Apple’s documentation, for viewDidLayoutSubviews(),

When the bounds change for a view controller’s view, the view adjusts the positions of its subviews and then the system calls this method.

Here I’m assuming that when the device gets rotated, the view’s frame gets updated and the bounds gets updated at the same time as well.

As for traitCollectionDidChange(), I understand that the traitCollection property of UIViewController contains information of all the traits belonging to the current iOS environment, which includes not only traits like the horizontal and vertical size classes, but also traits like user interface style, which is in charge of setting dark and light mode.

Hence my question is, which method should I be using to respond to changes in the interface orientation? Is there any computational advantage of using one method over the other/which one is more architecturally sound?

3

Answers


  1. That depends on what you want to do with that information.

    In my opinion, it’s better to use traitCollectionDidChange over viewDidLayoutSubviews unless it’s not possible.

    On average, traitCollectionDidChange would be called less during a view’s lifecycle. So if you don’t need the layout’s constant values, using viewDidLayoutSubviews would just add more computation to your app.

    To make it more clear:

    If you want to update your constraints or hide/show views based on the orientation, traitCollectionDidChange would suffice.

    If you want to know what a view’s size exactly is after rotation viewDidLayoutSubviews would be the method you’d want to utilize.


    Update:

    Please take a look at this answer as well.

    In most use cases you’d want to use option C. Only if you’re actually doing something regarding orientation, traitCollectionDidChange would be the correct way to go. Most of the time, their answer would be the best solution.

    Login or Signup to reply.
  2. When the user rotates their device, You can use the both traitCollectionDidChange(_:) and viewWillTransition(to:with:)
    methods to update the constraints, based on what you want to do with that information.

    Login or Signup to reply.
  3. Option C: viewWillTransition(to:with:) might be the better choice to update constraints. You can make a decision based on the new size and you can animate the changes by making use of the UIViewControllerTransitionCoordinator parameter. This will make the change in layout nice and smooth as part of the rotation animation.

    Keep in mind that you should not be focusing on the orientation. You should only focus on the view size of the view controller. Base all decisions on that size, not the orientation. By focusing on only the size, your views can better adapt to different devices and it can better adapt to multitasking on an iPad where the app may go from full screen to 2/3 screen to 1/2 screen, to 1/3 screen, all while the device orientation stays the same.


    Do note that traitCollectionDidChange(_:) may not even be called during an orientation change in some cases. Certain devices and certain iPad multitasking layouts will not result in either a vertical or horizontal class change when the device’s orientation changes. But the view size may change just enough that you would want to adjust constraints but you won’t be given the chance.


    The issue with viewDidLayoutSubviews is you end up changing the constraints after the rotation is complete and that leads to a less than clean change of layout. You can’t use viewWillLayoutSubviews because you won’t know the new size yet.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search