SwiftUI: KFImage, aspectRatio(), and layoutPriority()

Viewed 711

I’m having some issues with KFImage. It works fine with the placeholder image, until the remote image is loaded. It seems to be some interaction between .aspectRatio() and .layoutPriority(-1).

I have a kind of card with an image, and a couple text blocks beneath it. I want the image to be clipped to a view that has a specific aspect ratio, and whose width is dictated by the container (in the real app these live in a grid, and size will vary from device to device. I want the image to grow, rather than the spacing to grow).

Here’s what I get with the placeholder (the bubbles) and the loaded image (the aspect ratio test image). The placeholder image is 654 x 768, and the loaded image is 1080 x 1920. The aspect ratio of the placeholder is properly maintained, and it is clipped to the desired aspect ratio.

SwiftUI preview of proper placeholder behavior, but incorrect loaded image.

But as you can see, the loaded image is scaled non-uniformly to fit in the same aspect-ratio as the placeholder. The normal solution to that is to add .aspectRatio(.fill). But if I do that on KFImage, it blows up everything:

SwiftUI preview after adding .aspectRatio, both images displayed incorrectly.

Here’s the code. Note the .aspectRatio(contentMode: .fill) on KFImage is commented out. If you uncomment it, you get the second image above.

import SwiftUI

import Kingfisher


struct
SellerShowCell: View
{
    let     title           :   String
    let     secondary       :   String?
    var     startTime       :   Date?           =   nil
    var     thumbnailURL    :   URL?            =   nil
    
    var
    body: some View {
        VStack(alignment: .leading, spacing: 0.0) {
            ZStack(alignment: .topLeading) {
                //  Thumbnail background…
                
                ZStack {
                    KFImage(self.thumbnailURL)
                        .cancelOnDisappear(true)
                        .placeholder {
                            ZStack {
                                Color(.black)
                                Image("image_placeholder_background")
                                    .resizable()
                                    .aspectRatio(contentMode: .fill)
                                    .layoutPriority(-1)
                            }
                        }
                    .resizable()
//                  .aspectRatio(contentMode: .fill) //  Uncommenting this ruins the placeholder and allows the loaded image to dictate the parent size
//                  .layoutPriority(-1)              //  This does not have any obvious effect on KFImage
                }
                .aspectRatio(158.0 / 220.0, contentMode: .fit)
                .cornerRadius(16.0)
                
                Text("A Note")
                    .foregroundColor(.white)
                    .padding(8.0)
                    .background(Color.purple)
                    .clipShape(Capsule())
                    .padding([.top, .leading], 10.0)
            }
            
            //  Title…
            
            Text("\(self.title)")
                .multilineTextAlignment(.leading)
                .lineLimit(2)
                .font(.custom("Helvetica", size: 16.0).weight(.semibold))
                .foregroundColor(.black)
                .padding(.top, 12.0)
            
            //  Secondary…
            
            if let secondary = self.secondary {
                Text("\(secondary)")
                    .multilineTextAlignment(.leading)
                    .font(.custom("Helvetica Neue", size: 12.0).weight(.medium))
                    .foregroundColor(Color("secondary-color"))
                    .padding(.top, 12.0)
            }
        }
        .border(Color.green)
    }
}

struct SellerShowCell_Previews: PreviewProvider {
    static var previews: some View {
        ZStack {
            Color("main-tab-background")
                .ignoresSafeArea()
            VStack(spacing: 20.0) {
                SellerShowCell(title: "Here is a caption of sufficient length to be a couple of lines",
                                secondary: "Secondary Text",
                                thumbnailURL: nil)
                    .padding(.horizontal, 80)
                SellerShowCell(title: "Here is a caption of sufficient length to be a couple of lines",
                                secondary: "Secondary Text",
                                thumbnailURL: URL(string: "https://i.imgur.com/iH7Xe20.jpg")!)
                    .padding(.horizontal, 80)
            }
        }
    }
}
0 Answers
Related