SwiftUI Fundamentals

Feb 28 2023 · Swift 5.7, macOS Venture 13.1, Xcode 14.2

Part 1: SwiftUI Views

03. Modifiers

Episode complete

Play next episode

Next
About this episode

Leave a rating/review

See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 02. The View Protocol Next episode: 04. Challenge: Views & Modifiers
Transcript: 03. Modifiers

OK, we’re right where we left off in the last episode. We’ve got some text and a little swift image, here, and we’re looking to customize them a bit.

You might remember that I had you delete something from our initial “Hello, world!” app. It looked like this:

}
  🟢.padding()

This padding is a SwiftUI modifier. It pads your views with space around them. If you just use the empty parens, here, you’ll get a standard padding on all sides, and the system will figure out how much for you. But, like most modifiers, you can be more specific about what you want with some arguments.

So, for the Swift image, Start typing padding again and you should see four auto-complete options in the list. Select the one that gives you “edges” and “length”

Image(systemName: "swift")
  🟢.padding(/*@START_MENU_TOKEN@*/.all/*@END_MENU_TOKEN@*/, /*@START_MENU_TOKEN@*/10/*@END_MENU_TOKEN@*/)

This first part is an option set that lets you specify which edges you want padding applied to. So, you could just do the bottom, with .bottom

.padding(.bottom,

And sometimes, if you check the inspector over on the right, there’s a nice interface to adjust modifiers.

And that will always adjust the code to match! You could set a custom length for the edges, too, but this argument has a default value, so I’m just going to delete this 10 and let SwiftUI sort it out for me.

.padding([.top, .leading, .trailing]❌)

You may have noticed the “Frame” area in the attributes inspector. If you edit the size, here:

Edit to 100 x 100

You’ll see that update in the canvas and the code as well. Great! So, I’ve told you about exactly one modifier, and you found another in the attributes inspector. How might you discover more?

Just like finding more Views, try the library! The second tab is full of modifiers. As you can see, there’s multiple categories here. Lots of different things modifiers can do for you! There’s even a special section for Text modifiers and Image modifiers! To be able to “resize” the image, so it takes up more of that giant frame, try dragging this “Image Resizable” modifier onto the canvas and drop it over the little Swift image.

And now, you’ve got an error! “Some View” has no member “Resizable”. To sort this out, let’s talk about how all of these modifiers are actually working.

You know that modifiers are how you alter the appearance of a SwiftUI component. But, how does that happen? Remember, all of these SwiftUI views are Structs. Value types! So, when you add a modifier to a component, it isn’t really modifying the view. It’s returning a completely new View with the modifications you want already applied.

If you’ve chained together higher-order functions like map and filter before, this is a similar process. That’s true in a couple of important ways.

First, types matter! The resizable modifier is a method on the Image type, not the View protocol. So, you can only call it on an image. And, just as important, it’ll return an image.

Second, and related, order matters! In this example, both frame and padding are part of the View protocol, and they return some View.

If you apply either of those directly to an Image, you’re not going to get an Image back. The type changes. You’ll get some View, and that “resizable” method won’t be available to you.

But if you switch that around and use Resizable first.

Problem solved! You’ll run into the same issue when modifying Text.

If you go back to the Library… You’ll see quite a large section of Text modifiers! Let’s try one, how about Font Weight? Drag it over the Text in the canvas and drop it on top. Again, this needs to be applied directly to the Text component. You’ve got “Bold”, to start with, but you can adjust that. Either in code or in the attributes inspector!

Now, if you option click on the modifier… You’ll see that it returns Text. So, if you wanted to add another text-specific modifier, you could do that before fontWeight…

🟢.kerning(5.0)
.fontWeight(.Black)

Or after!

And the result there will be the same. There are other times the order of modifiers would change the result. For example, add a background modifier to the Swift image

	.background(Color.orange)

Each modifier is returning a new view and the modifiers are performed and returned in order from top-to-bottom.

So, right now, you’re making an Image, making a resizable image. Then adding padding on three sides, setting a frame size and finally a background color. But if you select this padding line and move it around with Option-Command left and right bracket…

See the difference when it comes before and after the frame size, or before and after the background? This is a perfect example of why order of modifiers is important.

If you want the background color to extend over all of that padding space, you need to add the padding first! If not, the padding should come last. You can also put some in both places!

🟢.padding()
.background(Color.orange)
.padding([.top, .leading, .trailing])

Fancy This can all take some practice, so I’ve got a challenge for you, next!