NEW: Join my free 100 Days of SwiftUI challenge today! >>

Polishing designs with fonts and colors

Paul Hudson    @twostraws   

Fully updated for Xcode 11 GM

We’ll add some more to our design in just a moment, but first let’s pause and make what we have look better.

Our menu item’s name is clearly the most important thing in each row, but it has the same font size as the price below. We can bring it up in size and weight by using the font() modifier, which accepts any of Apple’s Dynamic Type sizes.

So, something like this will make it stand out:

Text(item.name)
    .font(.headline)

As for the picture, it looks OK as it is, but with a little love it would look better. For example, we could apply a clipShape() modifier and ask it to be clipped to a circle shape:

Image(item.thumbnailImage)
    .clipShape(Circle())

Or we could apply a clipShape() modifier, then add an overlay() modifier so we place a shape on top of our image. For example, this will add a circle over the image, then give that circle a 2-point gray border:

Image(item.thumbnailImage)
    .clipShape(Circle())
    .overlay(Circle().stroke(Color.gray, lineWidth: 2))

OK, that’s enough styling – let’s look at something more complex.

If you look in menu.json you’ll see that each menu item has a string array of restrictions: “G” for containing gluten, “N” for containing nuts, “V” for being vegetarian friendly, and so on. We can use that to create colored icons representing what’s in the food at a glance, showing zero or more of them in each row as appropriate.

First, we need a dictionary of colors that we’ll use for each restriction type. Add this property to ItemRow:

static let colors: [String: Color] = ["D": .purple, "G": .black, "N": .red, "S": .blue, "V": .green]

Second, we need to loop over all the restrictions and put each one into a text view. Put this after the VStack containing the name and cost:

ForEach(item.restrictions) { restriction in
    Text(restriction)
}

Now we have a problem: that code won’t compile. As I mentioned earlier, we can put arrays into a ForEach as long as SwiftUI knows how to identify each item in the array uniquely. We solved that by making our sections and items conform to the Identifiable protocol, which uses the id property to identify items.

Here, though, we have an array of strings, so we can’t make them conform to Identifiable. Instead, we need something else: we need to tell Swift that the string itself is the identifier for each item. This can be done using the id parameter for ForEach, passing in \.self as its only parameter, like this:

ForEach(item.restrictions, id: \.self) { restriction in
    Text(restriction)
}

And now you should see the text “G” and “V” next to our example item in the Xcode preview.

That’s pretty dull, though, so let’s spice it up with some modifiers:

Text(restriction)
    .font(.caption)
    .fontWeight(.black)
    .padding(5)
    .background(Self.colors[restriction, default: .black])
    .clipShape(Circle())
    .foregroundColor(.white)

That will use a small, bold font with white text and a colored background, add a circular clipping shape, and add a little space around it so the text circles aren’t so near.

We’re going to do one more thing before we’re done with the design of this item row: we’re going to force the restriction text to be spaced apart from the rest of the row. SwiftUI has a dedicated view for this called Spacer, and I’d like you to place it just before the ForEach for our restrictions, like this:

Spacer()

ForEach(item.restrictions, id: \.self) {

That will automatically take up all available free space, meaning that our picture will now be on the far left and the restrictions on the far right.

Go ahead and run the project now and I think you’ll agree it looks great! Now think about how you might have accomplished all that using a UITableViewCell – it would take more code than you expect!

Tip: If you find your menu item labels being clipped, try adding .layoutPriority(1) to the VStack in ItemRow – that should give SwiftUI the hint that the items in the VStack should be shown in full. Hopefully this won’t be needed soon!

Further reading

LEARN SWIFTUI FOR FREE I have a massive, free SwiftUI video collection on YouTube teaching you how to build complete apps with SwiftUI – check it out!

Similar solutions…

MASTER SWIFT NOW
Buy Testing Swift Buy Practical iOS 12 Buy Pro Swift Buy Swift Design Patterns Buy Swift Coding Challenges Buy Server-Side Swift (Vapor Edition) Buy Server-Side Swift (Kitura Edition) Buy Hacking with macOS Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with Swift Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

Was this page useful? Let us know!

Average rating: 5.0/5