Today, I'm going to show you how to make sure your apps user interface looks great
on all screen sizes and orientations. You'll learn how to preview your user interface on a variety
of devices and screen sizes. I'll also tell you why the terms profile and landscape orientation
don't mean what they used to. You'll learn how to adjust your user interface based on the available
space on the screen. And finally, I'll leave you with my best tips on how to build a user interface
that looks great on all screen sizes. By the end of this tutorial you'll be able to build responsive,
Swift UI user interfaces. Hey, Code Crew, in case you're new here,
my name is Chris and welcome. I've been teaching Beginners how to build API since 2013, so if that's what you
want to do, you're in the right place. Now, if you're just starting out. I highly recommend that you check out the 14 day Beginner
challenge right over there. There's a whole community of people in our Code Crew form going through
that challenge right now. Alright, now let's dive
a date today's topic. So before we can even talk about how to fix a broken UI,
you first need to detect that your UI is broken and that means previewing it
in different devices and orientations. So make sure you have
the preview canvas open. If you're on one of your views,
simply click on that and go to canvas. You've probably discovered this yourself,
but you can change the simulator and that's going to change
how your UI is displayed. And you can sort of preview how it's going
to look on different devices is like this by changing the simulator, but it's
not a very efficient way to do it. If you look at your view code here at the very bottom for your views,
at least you're going to see a struct that is specifically for powering the
preview over here on the preview canvas. Now, what you can do here is add a modifier to customize what
device it's going to preview in. You can either do this through code so you can add a modifier called preview device
and then you can pass in a string and it has to be exactly one
of the simulator strings here. Even for example,
iphone Se second generation, you have to put in the brackets second
generation, basically the whole thing. Now I'm not going to type that out,
but let's type in iphone eight. You're going to see
that change right there. Another way to do it easier with less
typing is instead of typing it out by hand, you could just use
the attributes Inspector here. If you're looking at the preview and just change the device in the drop down and
it's going to accomplish the same thing. So there's iphone eight and there's
iphone Se second generation. As you can see that's the string there. Now doing it this way also lets you do multiple preview, so you don't
have to be restricted to previewing. You know, one thing at one time. So if you're targeting a handful of
devices, you can have multiple previews. So maybe this one's going to be iphone twelve, this one's going to be
iphone eight, and so on. And then all you need to do at a glance,
you can see your UI on multiple devices. So the next question is, how do you preview your UI
on different orientations? Well, in iOS 15, that's coming out in a couple of months,
there will be a new modifier that you can specify on your preview to define what
orientation it's going to display in. If you go into your project properties here, you can see portrait upside down,
landscape, left, landscape. Right.
So you're going to be able to specify one of these orientations, and that is
going to change what you see here. For now, though, currently, I was 14,
we don't have that modifier. So one other thing we can do is instead
customize the layout here, choose fixed. And then you are going to manually specify you see, it change that one to a square
because it's 100 within 100 height. But you can specify a width and height that makes
it in Landscape mode. One of the sites that you can use, which
is pretty handy, is iOS resolution com. And if you come here,
let's say you're targeting iphone eight, you're going to take the logical width
and the logical height right here. And then you're going to put in, well, if it's in landscape that the width
is going to be the long side. Right. So the width is going to be 667,
and the height is going to be 375. So that's what you're going to put in here and 667. And then you're going to see
that in Landscape, and you can even give this a name because it's
going to get confusing. So you can give it
a name here iphone eight landscape, and it's going to give you a title right here, and you can
name your other ones as well. Now, just going back
to you here for a second. If you're wondering what the difference
between the physical with and the logical with this, you'll notice that iphone
eight is a retina screen. So every every logical Pixel on your iphone is actually comprised of more
Pixel than it actually is. So that's why it looks so crisp and clear. And so you can see that the actual number of pixels on the screen is 750,
but in terms of the width, but the system is reporting 375,
same thing goes for the height. The actual number is 334,
but the repo Ted number of 667. So every Pixel very logical Pixel is actually going
to be made up of four physical pixels. Long story short, if you ask iphone eight,
how many pixels wide is it? It's going to give you
back 375 and not 750. So you use the logical
within the logical height. So just to recap for now, using this preview layout with a fixed
heighten width in landscape mode might be the best solution we
have now until iOS 15 rolls out. When we have a new modifier called
Preview Interface orientation, you can pass in one of these orientations,
and that's that all right. Now you know how to preview your user interface on a variety
of devices and screen sizes. Swift UI does a pretty good job with its
declared a syntax to arrange things so that your UI doesn't look
broken on various screen sizes. However, sometimes there may be a case where your UI doesn't look
quite the way you want. So you might be thinking, how do you
identify that specific scenario? Maybe that specific device on a specific orientation and you want to handle
that case just to give an example. Let's say that on an iphone eight, in landscape mode, your UI
looks a little bit busted. So now you're thinking,
how do I detect through code that the user is using an iphone eight and he or she
is holding it in landscape orientation? That's not what you want to do because
that is essentially a Band Aid solution. It's not recommended. There are a couple of reasons
why doing this is a bad idea. Let me explain.
The term is portrait and landscape have sort of lost their meaning because
now there exists split views in ipad. So in this case you have the device
in landscape orientation. But as you can see, the space that you have for your
API is a portrait sized area. So if you detect for landscape orientation
and you display your UI and landscape mode when you've only got a portrait sized
area space, it's going to look strange. Furthermore, detecting for and targeting
specific devices in your Xcode is a losing battle because Apple releases so
many new devices all the time. Instead, Apple wants you to use size
classes if you've never heard of them. These are a combination of attributes that can describe
the amount of space you have. First, you have regular height, which means that you have
expansive space vertically. Then you also have compact height, which means that you have a constrained
amount of space on the vertical axis. Next up, you have regular width. And lastly, you guessed it compact
with notice, there's no mention of device orientation here because it's just not how
you hold your device that might constrain your space, as you saw earlier with the
split screen ipad example and that's it. Using these four attributes, you can decide how you want
to lay out your user interface. So for example, in the Human Interface guidelines, you can see the variety
of devices and orientations can be described using a combination
of these size class attributes. Instead of detecting specifically
for a certain device and a certain orientation, you can detect for the size
class and that'll tell you the type of space your API currently
has to work with. If you really want the code to detect
the specific device and orientation that the user is using, it does exist,
but it's the old way of doing things. I'll provide some links in the description
if you're curious about that. But in this particular video,
we're going to go with the current best practices, which is to base our
user interface off of size classes. So that's what I'm going
to show you how to do. Alright. Now you know to use size classes. Next question, how do we detect the size
class from our view code in Swift? I well, it's already part of the view. You just have to read it and we're going
to use this Environment property wrapper. And very simply, you create a property
for the vertical size class and you do the same for the horizontal size class
and you can get the values of the current, whether it's regular or compact,
for the width and height. So let me give you an example. So first of all, we use the environment
wrapper and we specify the key path. So you can see here specify the key path
to the environment value. And in this particular case,
it is we vertical size class. And then you declare your
property like normal. So maybe we'll call this on the vertical. We'll call it vertical size class. This is going to be a type of
user interface size class set of values that indicates the visual
size available to the view. This is going to be optional because
this might not always be available. We're also going to do one for the horizontal and you specify the key
path to be the horizontal size class. Right. And that's the path to read
that value that's already there. Horizontal size class is going to be
type of user interface size class. And again, optional. And that's it. If these values exist and they're known, then they will be available for you in
these properties that you specified here. Since we have these two properties, it's just a simple case
of using if statements in here. And let's do an example
where this is an iphone twelve. Let's go into the Human interface guidelines and look at the size
classes for an iphone twelve. Alright. So this is portrait orientation in this first column in landscape
orientation here. So when it's in portrait mode,
it's compat with a regular height. Makes sense.
Now in landscape orientation, it is still compact with,
but it is also compact height. So compact and compact right versus portrait is compact
with and regular height. So really the only thing that changes
is the height right on the width. It's both compact with. So we are going to, let's say change this text label depending on
the height size class. This is the vertical size class. If it's regular, then we'll say portrait. If it's compact, then we'll say landscape. So. Let'S start with, we'll just
use an if statement here. If horizontal size class. And I guess we didn't really talk about
this user interface size class data type. So why don't we go and take
a look at what it is? So it is an enum, and the potential values for this is either compact and regular,
just like we talked about. So we're going to be checking against this, checking against
it for these values. So if horizontal size class is equal to regular, which means it's portrait,
then we are going to display this. We're just going to put portraits. If horizontal size class,
or we can just do else. I you know what? We'll do another else text unknown. Okay, so let's take
a look at what happens. We are going to launch the simulator. First of all, let's check on the project properties, what orientation
this supports by default. I don't think upside down is enabled,
so I had to enable that. But here's something that you might not
know on the devices where you have this this blocker here, it is not going
to go into upside down orientation. So you know, in the beginning
it says landscape. It's not detecting it properly,
but once you change it, this is not working.
You know why? Because I was looking
at the wrong size class. I should have been looking at the vertical
size class because that's height. Right. So maybe a better name for these
might be height size class. And with size class. So let's we should be checking for the height,
because for the iphone twelve, it's really the height size class
that changes across portrait orientation. So some of you who are watching
might have caught onto that. My mistake.
Sorry about that. Let's run this and try it again. Okay, so now it's portrait by flip it.
It's landscape. If I flip it again to upside down,
you'll see that nothing changes. Because on these devices with the blocker, it doesn't actually go into upside down
orientation by flip it again landscape. Flip it back to right side API.
Portrait. If you try it with another device such as
the iphone eight that doesn't have the blocker, you'll see that you actually
do get an upside down orientation. So we've got portrait, landscape, and this is upside down again. So you can see it properly
goes into portrait again. This is landscape. Number one, Try not to use any specific heights or widths in any
of the views that you're specifying. While it might look good in your current
layout, it becomes a liability for smaller or larger screen sizes
because it won't scale. Instead, you can specify relative heights and widths if you need to, and you can
do this using the Geometry reader. Now number three, Swift UI uses a declarative syntax,
which means that it decides how to arrange and lay out all of the
components in your view. And I would say most of the time it does a pretty good job,
but it would really help if you understood how the Swift UI views
and components play nicely together. And what I mean by that is understanding
the nature of how a Swift UI component reacts when you give it more
space or you take away its space. For example, an image component expands
to take up all of its available space, and same goes for a color component,
a button, or a text component, on the other hand, only takes
up as much space as it needs. The trick is to know the behavior of each of these elements and how it prefers
to display itself on the screen. That way, as you're putting these
different components into layout containers, you know how they are going
to interact with each other, and you can arrange them in a way where
the outcome is what you'd expect. Now, one way you can remind yourself about this is just to test out the various
components in an empty Xcode project. On the other hand, you can do what I
do is use a reference guide for me. I use this Swift UI Views Mastery from Big Mountain Studio,
so this is what I'm referring to. Text views pull in, whereas other components push out
and take up as much space as it can get. Same thing goes for the geometry reader. For example, this particular guide is really handy because
it goes through all of the elements in Swift UI and sort of explains to you
how they react and how they behave, and there's a lot of code snippets
with how to use them as well. This particular one is from Big Mountain Studio, and I find
myself occasionally flipping through it. When I forget about how a component
behaves, I'll leave a link in the description below in case you're
curious about checking this out. So now you know how to create fluid, dynamic user interfaces that work
well on any sort of screen size. If you want to learn how to design amazing looking user interfaces in Figma,
which is a design tool, or maybe you want to learn how to use
Figma itself, check out our design course right over there or some of the Figma
tutorials that we have done on YouTube. Lastly, if you liked this video and you want to see more, consider subscribing
and giving this video a thumbs up. Thanks for watching.
I'll see you in the next one.