Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

AsyncImage with a placeholder sizing to fit to aspect ratio and clipping

I’m trying to create an AsyncImage with a placeholder image. With the following constraints…

  1. The placeholder image may not have the same aspect ratio as the AsyncImage.
  2. The remote image may not have the same aspect ratio as the AsyncImage.
  3. The remote and placeholder image may not have the same aspect ratios.
  4. The aspect ratio of the AsyncImage is fixed.

The requirements…

  1. The placeholder and the remote image must be scaled to fill the aspect ratio of the AsyncImage.
  2. They must not be squashed.
  3. They must be clipped so that they do not overflow the bounds of the AsyncImage (set by the aspect ratio).

In my head this should be simple. 😅

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

But I just cannot get this to work without at least one of the requirements breaking.

This is the closest I’ve got so far but the AsyncImage is just not clipped so overflows beyond either the height or width.

You can paste this into Xcode and it will show the

import SwiftUI

let aspect = 1.5

struct TestView: View {
    var body: some View {
        AsyncImage(
            url: URL(string: "https://placekitten.com/1920/1080"),
            transaction: .init(animation: .easeIn(duration: 3)) // <- slow animation to show issue
        ) { phase in
            switch phase {
            case .success(let image):
                image
                    .resizable()
                    .scaledToFill()
                    .aspectRatio(aspect, contentMode: .fill)
                    .clipped()

            default:
                Image(systemName: "rectangle")
                    .resizable()
                    .scaledToFill()
                    .aspectRatio(aspect, contentMode: .fill)
                    .clipped()
                    .foregroundColor(.white)
            }
        }
        .aspectRatio(aspect, contentMode: .fill)
    }
}

struct TestView_Previews: PreviewProvider {
    static var previews: some View {
        VStack {
            TestView()
                .overlay {
                    // This overlay shows the correct rect but the image is just not cclipped.
                    Color.black
                        .opacity(0.5)
                        .aspectRatio(aspect, contentMode: .fit)
                }
                .padding()
                .aspectRatio(aspect, contentMode: .fit)
        }
        .background(Color.red)
        .padding()
    }
}

This gives me the following…

enter image description here

The red background is from the VStack. The black transparent overlay shows the aspect ratio I’m looking for based on the aspect set at the top of the file.

>Solution :

have you tried using a geometry reader to set the height and width of the image container?

You can use this to work out the required ratio. That’s the approach I would take.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading