How do I show an AsyncImage only after its downloaded?

545 views Asked by At

I am using AsyncImage to load remote images, once a certain condition is met ('ready' in the example), meanwhile I show a default placeholder image.

The problem I have is that while the remote image starts to download (when the condition is met), for a couple of seconds I see an empty blank space and everything I have underneath the image jumps up see "Some sample text" in the example below.

I would like to show the downloaded image only when it's ready, and in the meantime keep showing the placeholderImage.

I know I can put the placeholder image inside the last phase of AsyncImage (under else instead of EmptyView(), but it won't work for me because I will load new remote images one after the other, and I want to show the previous image again until the new one is ready, without a blank screen each time.

In simple terms I want the images to transition smoothly without a blank phase.

Code below (I simulate the condition 'ready' with a timer to illustrate)

    
    
    @State var ready:Bool = false

    var body: some View {
        VStack{
            if ready {
                AsyncImage(url: URL(string: "https://images.squarespace-cdn.com/content/v1/58b4791ad2b857c893179e34/1537971642021-LHW76T7O8JG0M4GLTSTP/IMG_2818.jpg"), scale: 3) { phase in
                    if let image = phase.image {
                        image
                            .resizable()
                            .scaledToFit()
                            .aspectRatio(contentMode: .fit)
                            .transition(.opacity)
                            .cornerRadius(1)
                    } else if phase.error != nil {
                        Color.blue // Indicates an error.
                    } else {
                        EmptyView()
                    }
                }
            } else {
                
                Image ("placeholderImage")
                    .resizable()
                    .scaledToFit()
            }
            
            Text ("Some sample text")
        }
        .onAppear(){
            do {
                Task{
                    try await Task.sleep(for: .seconds(5))
                    ready = true
                }
            }catch{
                print ("Timer error")
            }
        }
    }
} ```
1

There are 1 answers

4
Luke On

I want to show the previous image again until the new one is ready, without a blank screen each time

Can you maintain a variable of the last image that was fetched (initializing the variable to the placeholder image), and show that variable inside the else block in place of EmptyView?