Search code examples
iosswiftimageswiftui

How can I make the frame height dynamic to the height of the image so that the image wont get cropped?


if let postImageURL = post.imageURL {
  GeometryReader{ geometry in
     let size = geometry.size
        WebImage(url: postImageURL)
             .resizable()
             .aspectRatio(contentMode: .fit)
             .frame(width: size.width, height: size.height)
                            
             .onTapGesture {
                 isFullScreen = true
             }
           }
        .clipShape(RoundedRectangle(cornerRadius: 10, style: .continuous))
        .frame(height: 200)
}

this is my current code, here i have set the frame height to 200 and it makes the image which has more height look crapframe height: 200

so how can i make it dynamically adjust frame height without making the image overlap onto other image?

chatGPT suggested to remove the .frame(height: 200) line completely, but then the image every image becomes tiny.tiny image :(


Solution

  • // You can pass URL in below method I have mentioned, Where you we canfetch Orignal Size of Images.
    
    
    import SwiftUI
    final class  ContentViewModel : ObservableObject {
        @Published var postURL : URL?
        
        //MARK:  Method to get Orignal Image Height And Width
        func sizeOfImageAt(url: URL) -> CGSize? {
            var size: CGSize?
            let semaphore = DispatchSemaphore(value: 0)
            
            let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
                defer { semaphore.signal() }
                guard error == nil, let data = data else {
                    return
                }
                guard let source = CGImageSourceCreateWithData(data as CFData, nil) else {
                    return
                }
                let propertiesOptions = [kCGImageSourceShouldCache: false] as CFDictionary
                guard let properties = CGImageSourceCopyPropertiesAtIndex(source, 0, propertiesOptions) as? [CFString: Any] else {
                    return
                }
                if let width = properties[kCGImagePropertyPixelWidth] as? CGFloat,
                   let height = properties[kCGImagePropertyPixelHeight] as? CGFloat {
                    size = CGSize(width: width, height: height)
                }
            }
            task.resume()
            
            semaphore.wait()
            return size
        }
        
    }
    
    struct ContentView: View {
        @StateObject var contentVM = ContentViewModel()
        @State var height : CGFloat = 30
        var body: some View {
            VStack {
                
                AsyncImage(url: contentVM.postURL) { phase in
                    switch phase {
                    case .empty:
                        ProgressView()
                    case .success(let image):
                        image.resizable()
                            .scaledToFit()
                            .frame(height: height)
                        
                        // Method will fire when URL will change , (you can use onChange method)
                            .onReceive(self.contentVM.$postURL, perform: {  postData in
                                guard let url =  postData else { return }
                                height =     self.contentVM.sizeOfImageAt(url: url)?.height ?? 50
                                print("Height and Width ::: \(String(describing: self.contentVM.sizeOfImageAt(url: url)))")
                            })
                    case .failure:
                        Image(systemName: "photo")
                    @unknown default:
                        EmptyView()
                    }
                }
                .onAppear(perform: {
                    // Use for Explanation
                    contentVM.postURL = URL(string: "https://www.gstatic.com/webp/gallery3/1.sm.png")
                })
            }
            .padding()
        }
    }
    
    #Preview {
        ContentView()
    }