Xcode 13 Vary For Traits

What happened to the Vary For Traits button in Xcode 13? It was a handy way to create layouts with constraints that varied depending on the vertical and horizontal size class.

The Xcode team has had several attempts over the years at creating the user interface for building adaptive layouts. The Vary For Traits button put you in a mode where you could add and remove constraints for specific size class variations:

Vary For Traits button in Xcode 12

It was far from perfect and in Xcode 13 it’s gone. So if you can’t use the vary for traits button how do you create adaptive constraints in Xcode 13?

How To Vary Constraints In Xcode 13

The Xcode documentation hasn’t caught up yet but the answer seems to be to fall back to creating variations on the Installed property of the constraint. You’ll find that in the size inspector:

Installed property of a constraint in size inspector

That’s nothing new and changing it for each constraint is a pain. Luckily, Xcode 13 does make that a little bit easier than it used to be.

A Practical Example

Let’s build a layout with constraints that adapt to the vertical size class. Here’s my target layout on an iPhone SE (2nd generation) in portait (regular height) and landscape (compact height) orientations:

Portrait layout with red stop button vertically above text. Landscape layout with red stop button to the right of text.

The stop button moves from being on top of the text in portrait to being on the right (trailing) side of the text in landscape. That doesn’t match how a stack view works so I’m building the constraints myself. Both layouts use six constraints, three of which are common to both orientations (shown in red):

Portait and landscape layouts each with six constraints. Three constraints in red are common to both layouts

Let’s walk through how to do this in Xcode 13:

  1. To get started, let’s first build the portrait layout. I’m using a button with a filled-style, Title 1 font, large corner style and 10 point content insets on all sides. The label is using a title 2 font and I increased the root view margins to 20 points on all sides. Here’s how it looks in Interface Builder:

    Portrait layout in Interface Builder with six constraints

    The six constraints pin the button and label to the superview margins and add a standard amount of vertical spacing between the two views.

  2. Before switching to landscape we need to create a trait variation for the three regular-height specific constraints so they are only active when we have a regular height. Hold the command-key and select the three constraints in the document outline (Button leading, Label top and Label trailing):

    Three regular height specific constraints selected

  3. In the size inspector, click the [+] button next to the Installed property. Note that we are creating a trait variation for all three selected constraints:

    Add variation for installed property

  4. In the pop-up menu, change the Width to Any. Make sure you have the Height set to Regular. Click the Add Variation button:

    Add regular height, any width variation

  5. Deselect the default variation so that only the regular-height (hR) variation is selected:

    hR variation of Installed selected

    The three selected constraints are now only installed when we have a regular height. The canvas is in portrait (regular height) orientation so we still have a valid layout. You should not be seeing any Interface Builder warnings.

  6. Xcode 13 now has an orientation control in the canvas toolbar. Use it to change the canvas to landscape:

    Change orientation to landscape

    Interface Builder will now be showing layout warnings as we no longer have enough constraints installed. The regular-height specific constraints are dimmed in the document outline to show they are inactive:

    Regular height constraints dimmed in outline

  7. Re-position the views for the landscape layout and add the three landscape specific constraints:

    Three landscape constraints highlighted in outline

  8. Select the three new constraints in the document outline and use the size inspector to add a new trait variation on their Installed property:

    Any Width, Compact Height trait variation

    In the trait pop-up, change the Width to Any and make sure you have the Height set to Compact. Click the Add Variation button.

  9. Deselect the default variation, leave the compact height (hC) variation enabled:

    Compact height variation enabled

    The three selected constraints are now only installed when we have a compact height.

  10. You can now use the orientation control to switch back and forth between portrait and landscape. The layout should be working without warnings in both orientations. The document outline will also update to show the active constraints. Here’s how it looks in portrait:

    Final layout in portrait

In Summary

To build a layout with constraints that adapt to a change in size class:

  • Add the constraints for the first variation (e.g. regular height).
  • Create a trait variation for their Installed property.
  • Switch the canvas to the new variation (e.g. compact height). This may involve changing the orientation or changing the device (e.g to an iPad).
  • Reposition your views for this new layout.
  • Add the constraints specific to this layout variation.
  • Create a new trait variation for this second set of layout-specific constraints.

Remember to select all of the variant-specific constraints in the document outline before creating the variation.

Once you get used to it I’m not sure it’s any worse than using the Vary For Traits button. For layouts any more complex than this example I tend to switch to code. Give it a go and see what you think.

Learn More

If you’re struggling to build adaptive layouts with Auto Layout you might like my book Modern Auto Layout.