iosswiftswiftuihstack

Preventing a Text view from breaking when the font size is increased in SwiftUI (Dynamic type / accessibility)


I have a few views in an HStack which gives me a view like this

SwiftUI HStack

There are 3 images and 2 Text views in here

My goal is to support graceful dynamic text / font scaling for larger text sizes, that is scaling the images and the text views.

This works for the most part:

HStack SwiftUI Dynamic Text Accessibility HStack

HStack SwiftUI Dynamic Text Accessibility

My issue arises on really large sizes and with the text, the text itself seems break because it is within an HStack

HStack SwiftUI Dynamic font large text

What I desire is for the 19.5 to be in 1 line and the the 20 to be on another line rather than the 19.5 breaking - is this possible ?

I've tried things like applying .lineLimit() of 1 and nil to the text as I saw in some answers but that didn't work.

I've also tried applying .fixedSize(horizontal: false, vertical: true) to the text to no avail.

I use @ScaledMetric outlined in this answer to scale the image.

Happy to share any code, however, it is just a basic HStack with 3 image views and two text views.


Solution

  • Try applying . minimumScaleFactor in combination with .scaledToFit to the HStack with the Text elements:

    private var target: some View {
        Image(systemName: "target")
            .resizable()
            .scaledToFit()
            .foregroundStyle(.red)
            .frame(width: 40, height: 40)
    }
    
    var body: some View {
        HStack(spacing: 0) {
            target
            target
            target
            HStack(spacing: 0) {
                Text("19.5")
                    .foregroundStyle(.yellow)
                Text("/")
                    .foregroundStyle(.white)
                Text("20")
                    .foregroundStyle(.white)
            }
            .padding(.leading, 10)
            .font(.largeTitle)
            .minimumScaleFactor(0.1)
            .scaledToFit()
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(.black)
    }
    

    Screenshot