Font-sized Images

WWDC 2020: Text now provides an initializer that accepts a single Image, this blog post will be updated or removed to reflect that. For now here’s the correct code.

struct ContentView : View { @ObservedObject var character: Character var body: some View { HStack { Text(Image(character.imageName) .resizable()) Text( } .font(.title) } }

Often you need to include images inline in text, while being mindful of supporting all of the various user-customizable sizes of text, not to mention the accessibility sizes:

An image matched to each possible title font size

One way to do this is by creating a custom SF Symbol, but that involves individually drawing or hinting each possible size. This obviously gives the optimal result, but it’s not necessarily something we have the resource to do. In the case of user-supplied imagery such as a character portrait, it’s not even an option available to us.

There’s a nice trick to achieving this with any resizable image, and it builds on what we learned in views choose their own sizes, and secondary views.

Recall that a secondary view receives as its proposed size the chosen size of the view it’s attached to.

So what we need to do is attach the resizable Image as a secondary view to a Text view that will inherit the font-size from the environment and choose its size accordingly.

We can then remove the Text itself from the output using the .hidden modifier, while leaving the Image overlaid on top visible:

struct ContentView : View { @ObservedObject var character: Character var body: some View { HStack { Text("M") .hidden() .overlay( Image(character.imageName) .resizable() .aspectRatio(contentMode: .fit)) Text( } .font(.title) } }

Imagery used in previews by Kaiseto, original images and derived here licensed under Creative Commons 3.0 BY-NC-SA.