swiftuiuikitsf-symbols

Aligning Text with SF Symbols in SwiftUI Without Using Frame


In code like this, the varying aspect ratios and side margins of SF Symbols cause the starting positions of the text to be misaligned. How can I fix this? I want to avoid setting fixed frames to support Dynamic Type. Using a Label instead of an HStack is also fine.

I want to vertically align the icons to the center without disrupting their size balance, and also align the starting position of the text.

struct ContentView: View {
    var body: some View {
        VStack {
            HStack {
                Image(systemName: "pencil")
                Text("This is Text")
                Spacer()
            }
            HStack {
                Image(systemName: "folder")
                Text("This is Text")
                Spacer()
            }
        }
    }
}

Image

This is what I aim for 👇 It can be achieved by using a Label within a Form.

Image2


Solution

  • I think you will need to set a .frame on the images, but you can use a ScaledMetric as the size. This way, it will adapt to different dynamic font sizes.

    Here is an elaborated example:

    struct LabelExamples: View {
        @ScaledMetric private var imageWidth: CGFloat = 22.0
        @ScaledMetric private var imageHeight: CGFloat = 18.0
    
        var body: some View {
            VStack {
                HStack {
                     Image(systemName: "pencil")
                        .resizable()
                        .scaledToFit()
                        .frame(width: imageWidth, height: imageHeight)
                     Text("This is Text")
                     Spacer()
                 }
                 HStack {
                     Image(systemName: "folder")
                         .resizable()
                         .scaledToFit()
                         .frame(width: imageWidth, height: imageHeight)
                     Text("This is Text")
                     Spacer()
                 }
             }
        }
    }
    
    struct ContentView: View {
        var body: some View {
            VStack(spacing: 20) {
                LabelExamples()
                    .dynamicTypeSize(.xSmall)
                LabelExamples()
                    .dynamicTypeSize(.large)
                LabelExamples()
                    .dynamicTypeSize(.xxxLarge)
             }
            .frame(width: 200)
        }
    }
    

    Screenshot