Override traitCollection of UIView

I am using a UIView with a nib as a template for a UIImage that I am generating, and I want to handle the output of the iPad in landscape differently than portrait. The best way I have figured I can do that is by setting up my landscape view for horizontal Regular, vertical Compact traits in the nib and assigning those traits before generating the image.

I have tried using the performAsCurrent method which successfully changes the UITraitCollection.current value but does not affect my UIView traitCollection property, and I have tried overriding the traitCollection getter in the UIView class which returns the error:

Class overrides the -traitCollection getter, which is not supported. If you're trying to override traits, you must use the appropriate API.

Is there a way to do this for a UIView that is never drawn to the screen?

Accepted Reply

The only supported APIs for changing the horizontal/vertical size class traits are the following:

UIPresentationController overrideTraitCollection https://developer.apple.com/documentation/uikit/uipresentationcontroller/1618335-overridetraitcollection

UIViewController setOverrideTraitCollection(_:forChild:) https://developer.apple.com/documentation/uikit/uiviewcontroller/1621406-setoverridetraitcollection

There isn't a way to change/override the size class traits of a UIView, so you will need to use one of the above APIs with the view inside of a view controller (and/or presentation), or modify your UIView's code to avoid using the size class traits directly and instead base its layout on your own properties which you control.

  • Thanks for the great feedback. I have switched to nesting my UIView in a UIViewController which I then add as a child view controller to another controller. I can successfully override the child view controller's trait collection, but the child view controller's view trait collection property does not seem to inherit the change and so when I call layoutIfNeeded(), the layout does not reflect the new trait collection. Can you suggest how to ensure the child view controller's view inherits the setOverrideTraitCollection change?

  • Interestingly, if I override traitCollectionDidChange in my child view controller, add a breakpoint there, and print the traitCollection of its view in the debugger, it shows the inherited traitCollection correctly and then proceeds to lay out the view properly. But unless I do that print, the value stays the old one for the child view controller's view.

Add a Comment

Replies

The only supported APIs for changing the horizontal/vertical size class traits are the following:

UIPresentationController overrideTraitCollection https://developer.apple.com/documentation/uikit/uipresentationcontroller/1618335-overridetraitcollection

UIViewController setOverrideTraitCollection(_:forChild:) https://developer.apple.com/documentation/uikit/uiviewcontroller/1621406-setoverridetraitcollection

There isn't a way to change/override the size class traits of a UIView, so you will need to use one of the above APIs with the view inside of a view controller (and/or presentation), or modify your UIView's code to avoid using the size class traits directly and instead base its layout on your own properties which you control.

  • Thanks for the great feedback. I have switched to nesting my UIView in a UIViewController which I then add as a child view controller to another controller. I can successfully override the child view controller's trait collection, but the child view controller's view trait collection property does not seem to inherit the change and so when I call layoutIfNeeded(), the layout does not reflect the new trait collection. Can you suggest how to ensure the child view controller's view inherits the setOverrideTraitCollection change?

  • Interestingly, if I override traitCollectionDidChange in my child view controller, add a breakpoint there, and print the traitCollection of its view in the debugger, it shows the inherited traitCollection correctly and then proceeds to lay out the view properly. But unless I do that print, the value stays the old one for the child view controller's view.

Add a Comment