TruMan1
TruMan1

Reputation: 36078

How to dynamically size an image in SwiftUI for accessibility?

I have an image that I'm hard coding the size, but realized it's not scaling for larger size categories. How can I set a preferred size and let it scale up to different sizes automatically?

This is what my code looks like:

HStack(alignment: .top, spacing: 4) {
    Text("Some text")
    Button(action: { showAlert = true }) {
        Image(systemName: "questionmark.circle.fill")
            .resizable()
            .frame(width: 12, height: 12)
            .foregroundColor(.secondary)
    }
}

I also have other scenario where it's not using a SF Symbol:

Button(action: action) {
    Label(
        title: {
            Text(title)
                .foregroundColor(Color(.label))
        },
        icon: {
            Image("twitter")
                .resizable()
                .frame(width: 24, height: 24)
        }
    )
}

This is how it looks in preview in different sizes, but the images are tiny in the larger scales. How do I handle this to achieve accessibility?

enter image description here

Upvotes: 14

Views: 5121

Answers (2)

Asperi
Asperi

Reputation: 257693

SwiftUI 2.0 provides ScaledMetric for this purpose.

Here is a demo of solution. Tested with Xcode 12.1 / iOS 14.1

Normal text: demo2

Largest text: demo

struct TestScaledImage: View {
    @ScaledMetric var scale: CGFloat = 1     // << here !!
    var body: some View {
        HStack(alignment: .top, spacing: 4) {
            Text("Some text")
            Button(action: {  }) {
                Image(systemName: "questionmark.circle.fill")
                    .resizable()
                    .frame(width: 12 * scale, height: 12 * scale)  // << here !!
                    .foregroundColor(.secondary)
            }
        }
    }
}

Upvotes: 34

Sergio Bost
Sergio Bost

Reputation: 3209

Wrap your code in a GeometryReader

for example

HStack(alignment: .top, spacing: 4) {
    GeometryReader { geo in 
        Text("Some text")
        Button(action: { showAlert = true }) {
            Image(systemName: "questionmark.circle.fill")
                .resizable()
                .frame(width: geo.size.width / 9, height: geo.size.height / 9)
                .foregroundColor(.secondary)
        }
    }
}

Then just adjust to whatever suits you

A GeometryReader reads whatever the current devices width and height info is and allows you adjust that instead of hard coding.

Upvotes: 0

Related Questions