2 Construct Auto Layout with the Interface Builder¶
Interface Builder is a graphical user interface (GUI) for developers to create an app’s user interface (UI). With Interface Builder, developers can drag and drop UI objects onto a design canvas, and then use Auto Layout to create adaptive user interfaces for different screen sizes.
With Interface Builder, you can build most of your app’s UI without writing a single line of code. In the end, you’ll end up with an Interface Builder file, saved as either a storyboard or a .nib/.xib file.
In this chapter, you’ll learn:
- To use a storyboard to layout your app’s UI.
- The benefits and drawbacks of using storyboards.
- To use .nib/.xib to layout your app’s UI.
- The benefits and drawbacks of using .nib/.xib files.
Setting up the launch screen layout using a storyboard¶
Open MessagingApp.xcodeproj in the starter folder. Under the Storyboards group, open LaunchScreen.storyboard. You’ll see the following:
You want the background image view to fill the edges of the view controller’s view. The current storyboard preview device is the iPhone 8. On this device, the UI looks fine. But it’s time to scrutinize how the launch screen looks on other devices and screen sizes.
Previewing layouts on multiple screen sizes¶
Interface Builder’s Preview mode lets you see your screen layout on various devices without running the project on a simulator or device. Preview is useful, but you still have to keep in mind its limitations.
Although Preview is a handy tool, you should take what you see with a grain of salt. It’s important to understand that Preview mode shows design time layouts, and design time layouts don’t always match runtime layouts. This means that when you run your app, the actual view you see on a device can differ from the preview because of different runtime variables.
Nonetheless, using preview is a helpful starting point. When your layout isn’t runtime dependent, preview accurately depicts how a view will look on various screen sizes. For this reason, Preview mode is perfect for seeing how the launch screen looks on different screen sizes.
On the top-right hand corner of the editor, click the Adjust Editor Options button. From the drop-down menu, click Preview.
After the selection, you should see preview on the right panel:
Tip
Give in-use panels more space by hiding unused panels. Press Command-0 to show/hide the Navigator panel. Press Command-Option-0 to show/hide the Inspectors panel.
You can delete devices from the preview panel. This is advantageous when you want to preview a different set of devices or arrange the preview devices in a different order. You’ll do the latter.
On the preview panel, select the iPhone 8 device. Press delete to remove the device. Then, click + for a list of devices you can preview.
Add the following devices to preview:
- iPhone SE
- iPhone 8
- iPhone 11 Pro Max
- iPad Pro 9.7” - Full Screen
- iPad Pro 12.9” (3rd generation) - Full Screen
Now, your workspace window will look like this:
You’ve discovered a layout problem! For devices larger than iPhone 8, the background image view doesn’t fill the view’s edges. You’re going to fix this.
The launch screen user interface is not yet able to adapt itself to different screen sizes. At the moment, the background image view is positioned at a fixed coordinate and size. It’s likely that your app’s users will use more than just the iPhone 8. It can vary greatly, which means this is a great opportunity to use Auto Layout.
Adding constraints¶
The first thing you’ll learn is how to add constraints to a view in Interface Builder.
Since you no longer need the preview now, click Adjust Editor Options. From the drop-down menu, select Show Editor Only.
In Interface Builder, you can use the Add New Constraints menu to add new constraints to a view.
In the editor, select background image view. On the bottom-right corner of the editor, click Add New Constraints.
At this point, the Add New Constraints menu appears.
The square in the middle represents the selected view. The four red “beams” represent constraints relative to the view’s top, bottom, left and right edges. The text field next to the beam specifies the constraint’s constant value.
Click all four red beams for top, bottom, leading and trailing edge constraints. Make sure the constraint constants are all set to 0. Click Add 4 Constraints to add the constraints.
Open Preview. With the same devices on preview, you’ll see this:
The background image view fills the view controller’s view on all devices except for the iPhone 11 Pro Max and the iPad Pro 12.9” (3rd generation). On the iPhone, you can see white areas above and below the background view. On the iPad Pro 12.9”, you see a white area below the background view.
On the Preview panel, hover your cursor over the iPhone 11 Pro Max. Click the rotation button to rotate the device’s orientation from portrait to landscape. You’ll see that the iPhone 11 Pro Max in landscape orientation has a noticeable margin around the background image view.
The background image view doesn’t go all the way to the edges of the view controller’s view on the iPhone 11 Pro Max. This is due to the Safe Area layout guide. The Safe Area layout guide makes it easier to create constraints in a way where content doesn’t get obstructed on a device with a sensor notch or a rounded screen. The iPhone 11 Pro Max is one of those devices.
Editing constraints¶
The Safe Area layout guide helps prevent obscured content. However, with this background image view, you want to have it fill the screen edges on every device.
In the editor, click View as: iPhone 8 to open the preview device selection panel. Select iPhone 11 Pro Max.
This switches the storyboard’s preview device to iPhone 11 Pro Max. This isn’t necessary to edit the constraint. However, this does help you see the changes around the edges of the device in the storyboard.
Select background image view in the storyboard. Open the Inspectors panel, and select Size inspector. Look at the constraints section.
The background image view has four constraints. All of the constraints are relative to the Safe Area. You’re going to update each constraint’s relative item to the superview.
For each of the constraints, do the following:
- Double-click the constraint. This shows the constraint’s details in the Size inspector.
- Click the Second Item drop-down menu. Select Superview to replace Safe Area.
- Set the constant to 0.
Afterward, the Constraints section will look like this:
In Preview mode, you’ll see the background view fill all of the edges on every device in portrait orientation:
You’ll also see the background view fill all of the edges in landscape orientation:
Great! Now, open the editor. Switch the storyboard’s preview device back to the iPhone 8.
Constraint inequalities¶
The background image view uses equality constraints. In addition to equality constraints, you can also create inequality constraints using Auto Layout.
There are instances where you want to offer your constraints more flexibility than equality constraints do. Inequality constraints allow a view’s attribute to be a range of numbers.
For example, a view’s leading edge can space between 0 and 20 from the superview. The final constraint leading space value will be determined by different variables, which you’ll see throughout different parts of the book. The idea behind inequality constraints is to let Auto Layout position or size within a value range.
It’s time to create some inequality constraints.
Implementation¶
Are you ready to spice up the launch screen? Fantastic!
You’ll add a logo image view with the Ray Wenderlich logo to the launch screen. Using constraints inequality, you’ll make the logo image view size and position according to screen width while simultaneously maintaining a width-to-height aspect ratio.
In the editor, drag a UIImageView onto the launch screen view controller’s view. Using the Attributes inspector, set the image view’s image to rw-logo. Set the image’s content mode to Scale to Fill.
Preview the launch screen. It will look something like this:
In the editor, select the logo image view. In the bottom-right of the editor, click the Alignmenu.
Align the logo image view vertically and horizontally inside the container and click the button to add the two constraints.
Once you add the constraints, look at the preview; it’ll look like this:
This is a great example of intrinsic size. The size of the rw-logo image causes the UIImageView to have an intrinsic size. Without any other size constraints, the image view’s intrinsic size defines the view’s size. Although this image view looks decent on iPads, there’s a lot of room for improvement on iPhones.
Add the following constraints to the logo image view:
- A leading constraint with a 20 constant.
- A trailing constraint with a 20 constant.
Also, add an aspect ratio constraint:
Ensure that the aspect ratio constraint’s multiplier value is 1:1; this keeps the image view’s width equal to its height. To set the aspect ratio constraint’s multiplier, open the logo image view’s Size inspector. Double-click the aspect ratio constraint and enter 1:1 in the Multiplier text field.
In preview, the launch screen looks like this in portrait:
And like this in landscape:
In portrait view, the logo image view is oversized on the larger devices. In landscape, the image is obscured on all devices. You’re going to fix the layout for landscape orientation first.
Click the View as button. Then, select landscape in the orientation menu to change the storyboard’s preview device orientation.
Next, add the following constraints to the logo image view:
- A top constraint with a 20 constant.
- A bottom constraint with a 20 constant.
This keeps the logo image view from expanding over the vertical edges of the screen.
At this time, with the Issue navigator selected, you’ll see a build time warning with six conflicting constraints.
The layout engine is unable to simultaneously satisfy all of the logo image view’s constraints on the preview device size. Your editor will look something like this:
The issue is that you told Auto Layout that this image should be exactly 20 points from the left and the top. You also told Auto Layout that the image should have a 1:1 aspect ratio and center vertically and horizontally in the container. To simultaneously satisfy these constraints, the logo image view’s leading edge spacing has to exceed 20 on the preview device.
You could simply resolve this issue by removing the aspect ratio constraint. However, the aspect ratio of the image view is a requirement. The aspect ratio constraint keeps the logo image’s width and height equal to each other.
This is where inequality constraints can come into play. You don’t need the image’s leading edge to space exactly 20 points from the superview’s leading edge. You just need it to be at least 20 points from the edge and having the constraint take on a value greater than 20 is fine too.
Now, you’ll set the leading and trailing constraints’ relations to greater than or equal to. Here’s one way to update the constraint relation.
Select the logo image view. Open the Size inspector. Double-click the leading constraint. Once you see the constraint details panel, set the constraint relation to Greater Than or Equal from the relation drop-down menu.
After updating the constraint relation, the constraint will look like this:
Here’s another way to update the constraint relation. Select the logo image view. Open the Size inspector.
Now, click the Edit button on the trailing constraint. Then, click relation drop-down menu and select ≥ to set the inequality.
Afterward, your launch screen preview will look something like this in landscape:
Flip the devices to portrait in preview, and you’ll see this:
The logo image view is unable to satisfy all constraints with current device layout conditions. Similar to the scenario above, you can resolve the conflicting constraints buildtime warning by applying inequality constraints. This enables the logo image view to be flexible with the top and bottom spacing while conforming to the aspect ratio constraint on the vertical axis.
Set the top and bottom constraint relations to greater than or equal.
After the updated constraint relations, your launch screen preview looks like this in portrait:
As for the landscape orientation, that looks like this:
The launch screen is looking great and ready for different device sizes. Great job!
Pros/cons and who is it for?¶
Apple has taken something complex and turned it into something comparatively elegant. However, as with any solution, there are benefits and drawbacks.
Here are five pros of using storyboard:
- As the name implies, storyboards become a flow diagram. A storyboard makes visualization of the app’s flow vivid and obvious. You can tell by looking at a storyboard that the first view controller transitions to the second view controller with the segue indicator arrow. You can see the UI elements inside of a view controller. Also, available to you with a storyboard is the real-time update of how UI objects appear after constraint updates. These are three examples of the many visual benefits from storyboards.
- Almost every iOS developer learns to construct layouts in storyboards at some point today. Under the circumstance where the storyboard complexity is low, on-boarding a developer into your project is easier in the sense that more developers are well-versed with storyboards than other methods of layout construction. Plus, most developers start out learning to construct Auto Layout constraints using storyboards.
- Apple pushes developers to construct layouts in storyboards with Interface Builder. Historically, Apple has continued to add features, improve upon existing features and provide developer support materials on constructing layouts in Interface Builder. You can expect to continue support from Apple with the development of Interface Builder. Apple has emitted its aura of pushing everyone to learn to code. Using Interface Builder is often dramatically less intimidating than building layouts in other methods like code.
- Building out your layout in the Interface Builder gives you the benefits of Apple’s behind the scene optimization of your layouts.
- Layout changes to your UI objects are reflected in the storyboard. This omits the need to build and run your app to see how your UI objects have changed. Consequently, this saves time.
Here are five cons of using storyboard:
- The infamous merge conflicts resolution problem. Merge conflicts are easy to come by when two or more developers make changes onto a single storyboard. Because storyboard files are stored as XML, the files are not exactly the most reader-friendly. When there are multiple changes from different developers using the same storyboard file, you may find yourself spending some time resolving merge conflicts. This effect can compound over time. Apple has taken measures to make merge conflicts less of a problem with more readable XML files and by making it easier to split up large storyboard files. However, the storyboard merge conflict problem persists.
- Do you want everything that has to do with the app UI in one place? Interface Builder can be problematic as your app complexity grows. You can set your UI to different values to do different things in Interface Builder with storyboards. However, at the same time, you can also make changes to your UI objects in code. You may wonder why your UI looks completely different on your device than the storyboard. In addition, you may find your app requiring both storyboard and code maintenance instead of one or the other. This can lead to presentation logic ambiguities.
- Re-usability is vital for maintainability. In the scenarios of where you want to build on top of the existing view controller or reuse certain UI elements from a view controller you storyboard, then you are out of luck. The storyboard does not support this.
- Interface Builder is a graphical user interface built as an additional layer for generating XML codes. The additional layer makes Interface Builder prone to UI bugs on the editor and at runtime. The reliability of this layer is dependent on the Xcode team.
- Using Interface builder increases compile time compared to code implementation. As complexity increases in your storyboard files, compile-time can take up a chunk of development time. Consider the compounding effect of development time.
When deciding on your approach, take consideration of your variabilities and the pros and cons of each layout construction approach. Generally, apps that are simple in design and presentation logic make storyboard a great partner in crime.
Using Xibs¶
Have you ever heard about .xib files? Even if you say no, I bet you’ve probably used them. Those screens that are part of a scene in your storyboard are .xib files. The only difference is that, thanks to the storyboard, you have some benefits, like segues and a nice look at the workflow of your app. Before carrying on and to avoid ambiguity, it’s important to understand the differences between .xib and .nib files.
As found in the official Apple documentation at https://apple.co/2YVj8CO:
“A .nib file describes the visual elements of your application’s user interface. This includes windows, views, controls, and many others. It can also describe non-visual elements, such as the objects in your application that manage your windows and views.”
Usually, people refer to .nib and .xib as the same thing; the difference relies on the fact that .xibs are only flat files — XML files — meanwhile, .nibs are deployable files. To use a .xib file in the final compiled app, it must be compiled into a .nib.
How to achieve modularity with .xib¶
If you’re working on a team, it can be pretty rough to deal with merge conflicts when everybody is using a single storyboard. That’s why you need a way to work on screens in a more decoupled way.
Sometimes, you need to create parts of the user interface that should be reusable and independent. For those cases, .xibs are a really good option. It’s similar to the way you create storyboards, but with no attachment. So you can have graphics interfaces that don’t depend on other views or transitions.
The .xib object life cycle¶
It’s important to understand how .nibs files are loaded, so you can create better interfaces that behave as expected and have good performance. The following diagram shows the chain of steps executed to display a view using a nib:
- Load the contents of the file and any referenced resource files into memory.
- Instantiate all of the objects inside the .xib file; by default, every object receives an
init(coder:)
message. - Reestablish all Outlet and Action Connections.
- Call
awakeFromNib()
. - Display the view.
Practical use case¶
Open MessagingApp.xcodeproj in the starter folder. Build and run. You can see a contact list; it’s a simple table view that shows the name of the contact and has an accessory info button on the right. But if you press the info button, nothing happens. Well, it’s time to do something about that!
Stop the project and expand to Views folder on the Project navigator. Right-click over the ContactPreview folder and select New File….
Under the User Interface section, select View and click Next.
In the Save As text entry, enter ContactPreviewView and press Create. This creates a ContactPreviewView.xib, which is just an empty view, for now.
Select the View and go to the Attributes inspector. On the simulated metrics section, select Freeform for the size attribute.
Now, go to the Size inspector, and set the width and height equal to 150.
Finally, go to the Attributes inspector, and for background, select black color. The view will look smaller now — just remember these are simulated metrics to help give you a better idea of how the view will look at runtime. You still need to set the necessary dimensions and position for the view, also known as constraints.
You need to assign a file owner to the new .xib file, so you can instantiate it and use it in your app.
In the same group, add another new file. Select Cocoa Touch Class with UIView
subclass and name it ContactPreviewView.
Open ContactPreviewView.xib. Select File’s Owner in the document outline, and go to the Identity inspector. Select ContactPreviewView for the class attribute.
Add the following code, starting at the beginning, inside the ContactPreviewView
class in the ContactPreviewView.swift file:
// 1
override init(frame: CGRect) {
super.init(frame: frame)
loadView()
}
// 2
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
loadView()
}
func loadView() {
// 3
let bundle = Bundle(for: ContactPreviewView.self)
// 4
let nib =
UINib(nibName: "ContactPreviewView", bundle: bundle)
// 5
let view = nib.instantiate(withOwner: self).first as! UIView
// 6
view.frame = bounds
// 7
addSubview(view)
}
Here’s what you did:
- Override the
init(frame:)
constructor so that you can callloadView()
. - Override the required
init(coder:)
constructor so that you can callloadView()
. Since it’s a required constructor, not implementing it will cause an error. - Get a reference to the bundle that contains the ContactPreviewView .xib file.
- Create an instance of the ContactPreviewView .xib, indicating its containing bundle.
- Instantiate the view and assign the owner, which is the current class.
- Set
view.frame
equal tobounds
. This givesview
the same dimensions as its parent. - Add the instantiated view to the current view.
You can now use ContactPreviewView
anywhere in your project, such as in ContactListTableViewController
.
Open ContactListTableViewController.swift (in the Controllers group) and add this code immediately after the cellIdentififer
declaration:
@IBOutlet var contactPreviewView: ContactPreviewView!
This code creates an outlet to reference the custom view. Now, add the custom view to the Contacts storyboard.
Open Contacts.storyboard. Press Command-Shift-L and look for uiview.
Drag the view object below the Exit item in the document outline.
Select the view. In the Identity inspector, select ContactPreviewView
for the class attribute.
Control-drag from ContactListTableViewController to the ContactPreviewView. An outlets popup will appear; select contactPreviewView.
It’s time to set up the info accessory button on the Contact List.
Go to ContactListTableViewController.swift and type the following code at the end of the class:
// MARK: - Setup Contact Preview
override func tableView(_ tableView: UITableView,
accessoryButtonTappedForRowWith indexPath: IndexPath) {
// 1
let contact = contacts[indexPath.row]
// 2
view.addSubview(contactPreviewView)
// 3
contactPreviewView
.translatesAutoresizingMaskIntoConstraints = false
// 4
NSLayoutConstraint.activate([
contactPreviewView.widthAnchor.constraint(
equalToConstant: 150),
contactPreviewView.heightAnchor.constraint(
equalToConstant: 150),
contactPreviewView.centerXAnchor.constraint(
equalTo: view.centerXAnchor),
contactPreviewView.centerYAnchor.constraint(
equalTo: view.centerYAnchor)
])
// 5
contactPreviewView.transform =
CGAffineTransform(scaleX: 1.25, y: 1.25)
contactPreviewView.alpha = 0
// 6
UIView.animate(withDuration: 0.3) { [weak self] in
guard let self = self else { return }
self.contactPreviewView.alpha = 1
self.contactPreviewView.transform =
CGAffineTransform.identity
}
}
Here’s what you did:
- Get the corresponding contact using
indexPath.row
as the index. - Add the new view to the current main view.
- Set the constraints to make sure the view has a size of 150×150 and is centered vertically and horizontally.
- Use the NSLayoutConstraint.activate(_:) to active sizing and positioning constraints for contactPreviewView.
- Start with the view 1.25 times larger than normal and fully transparent.
- Create an animation to shrink the view down to normal and fade in to fully opaque.
Build and run. Tap any of the accessory info buttons; you’ll see a black square showing at the center of the screen.
The view is showing as expected. It’s time to add some content.
Open ContactPreviewView.xib. Select the View element in the document outline and change the background in the Attributes inspector to rw-light.
Press Command-Shift-L and type image view. Drag and drop the image view inside the blank view.
Press Command-Shift-L again, and this time look for a label. Once you find it, drag the label and drop it where you dropped the image view.
Select the Image View and click Add New Constraints on the bottom right corner. Set the top constraint to 25, width to 80 and select the Aspect Ratio checkbox. Click Add 3 Constraints:
In the document outline, Control-drag from the Image View to the View object.
From the popup that just appeared, select Center Horizontally in Safe Area.
Now, you’ll add some constraints to the label. Select Label and then Control-drag until you select the Image View. From the popup that just appeared, select Vertical Spacing.
Select Label and Control-drag until you select the View, and select Center Horizontally in Safe Area.
You now have the view all set up. Don’t worry if it doesn’t look good yet; you’ll fix that in a moment.
Go to ContactPreviewView.swift, and immediately after the first open brace, add the following code:
@IBOutlet var photoImageView: UIImageView!
@IBOutlet var nameLabel: UILabel!
@IBOutlet var contentView: UIView!
Here, you create three outlets that will connect to the label, image view and the content view of the .xib file. To make those connections, go back to ContactPreviewView.xib. Select the File’s Owner item and go to the Connections inspector. Connect each outlet with its corresponding element. Do that by dragging from the circle at the right side of each outlet to the element. . At the end your connections should look like this:
Time to set up the data to display. Go to ContactListTableViewController.swift and, immediately before view.addSubview(contactPreviewView)
, add the following code:
contactPreviewView.nameLabel.text = contact.name
contactPreviewView.photoImageView.image =
UIImage(named: contact.photo)
This piece of code fills the name label and the image view with its corresponding data.
Build and run. Tap any of the accessory info buttons, and you’ll see the contact preview. Currently, there’s no way to dismiss this modal. You need to fix that.
First, set up an animation to hide the Contact Preview view. Add this block of code at the end of ContactListTableViewController
.
@objc private func hideContactPreview() {
// 1
UIView.animate(withDuration: 0.3, animations: { [weak self] in
guard let self = self else { return }
self.contactPreviewView.transform =
CGAffineTransform(scaleX: 1.25, y: 1.25)
self.contactPreviewView.alpha = 0
}) { (success) in
// 2
self.contactPreviewView.removeFromSuperview()
}
}
Here’s what you did:
- Create an animation to scale the view up and fade it out.
- Remove the view when the animation ends.
Next, you need to create a function to set up the gesture recognizer. Add this code after hideContactPreview
:
private func configureGestures() {
// 1
let tapGesture = UITapGestureRecognizer(
target: self,
action: #selector(hideContactPreview))
// 2
contactPreviewView.addGestureRecognizer(tapGesture)
view.addGestureRecognizer(tapGesture)
}
Here’s what you did:
- Create a
UITapGestureRecognizer
that will triggerhideContactPreview
when tapped. - Add the gesture to
contactPreviewView
and the view. This code allows the method to be called when the user taps the view or the popup view.
Finally, add the following code in viewDidLoad()
:
configureGestures()
After the view controller’s view has loaded, you’ll invoke registering a tap gesture onto the view.
Build and run.
At this point, the contact preview doesn’t display as expected. Therefore, it’s necessary to edit the constraints to give the correct values.
Editing constraints using Interface Builder¶
Open ContactPreviewView.xib. Select the Photo Image View, and on the right side of the Interface Builder, select the Size inspector.
Click Edit on the constraint that contains the text Ratio to…, and set the multiplier to be equal to 1:1, and then press Enter.
Select the Name Label in the document outline and go to the Size inspector. Click Editon the constraint that starts with Top Space to…. Make the constant equal to 10, and then press Enter.
Build and run.
You now have a nice looking and reusable contact preview modal.
Pros/cons and who is it for?¶
.xib files can offer many advantages, especially when compared to storyboards. But remember, you can use both tools in your project.
Pros¶
- Since .xibs have less UI described in one file, it can be easier to manage or avoid conflicts, compared to storyboards.
- It’s easy to reuse a .xib file throughout a project, to avoid creating duplicated interfaces, or even use them in other projects.
- It can help to have part of the system more encapsulated.
- It shines when you need to create custom controls. If you’re going to use Interface Builder to create custom controls, .xib files are the way to go.
Cons¶
- You can’t have relationships between screens, something that’s simple and useful while using storyboards.
- No visualization of the workflow of your app. That’s something you can only have with storyboards.
- If the view is dynamic, it can be difficult to create using .xibs.
When deciding on using .xib files, take consideration of the problem you and your team are facing. Then, account for the pros and cons of utilizing .xib files. Generally, Interface Builder users see .xib files offer significant modularity and reusability benefits.
Challenges¶
Great job making it this far. Here are a few challenges to help solidify what you learned.
Create a custom label and position and shape the custom label according to the following specifications:
- Add a label to the view controller in Profile.storyboard. This will be referred to as the profile name label.
- Center the profile name label horizontally with the profile image view.
- Make the profile name label and profile image view have equal widths.
- Position the profile name label 16 points from the bottom of the profile image view.
- Make sure the bottom of the profile name label is at least 20 points from the bottom of the safe area.
- Under the project’s General/Deployment Info settings, set the main interface to Profile.storyboard. Afterward, run your project to see how your user interface layout looks on the simulator.
After attempting the challenge, you can use the final project file to compare your implementation.
Key points¶
- The preview feature helps you see your UI on different screen sizes without running the project on a simulator or device.
- You can use the Add New Constraints button to apply Auto Layout constraints in Interface Builder.
- You can use the Attributes inspector to set the object’s properties.
- Remember to account for the Safe Area layout guide to ensure devices with a notch display as intended at runtime.
- You can set equality and inequality constraint relations between items.
- The Issue navigator can show you the conflicting constraints in a storyboard.
- Using .xib files is a great way to achieve modularity.
- There are benefits and drawbacks to every tool. Building Auto Layout constraints in storyboards or .xib files with Interface builder is no exception. Consider the pros and cons of each to conclude an optimized solution for what you need.