我应该如何在 SwiftUI 中实现缩减采样和加载图像:同步还是异步?

How should I implement downsampling and loading images in SwiftUI: synchronously or asynchronously?

提问人:idhun90 提问时间:7/29/2023 更新时间:7/29/2023 访问量:34

问:

我需要对存储在 CoreData 中的图像进行缩减采样,以显示特定大小的图像。

目前,我已经同步实现了它,但是当sheetView从底部出现时,图像动画并不流畅。

我应该对它进行动画处理,还是缩减采样是一项如此大的任务,我应该异步执行?我不确定何时同步进行,何时异步进行,请帮忙。

import SwiftUI

struct DetailView: View {
    @Environment(\.managedObjectContext) private var moc
    @ObservedObject var item: ItemEntity
    @State private var uiImage: UIImage? = nil
    
    @Environment(\.dismiss) private var dismiss
    
    var safeArea: EdgeInsets
    var size: CGSize
    private let spacing: CGFloat = 3
    
    var body: some View {
        ScrollView(showsIndicators: false) {
            VStack(spacing: 2) {
                imageHeaderView
            }
        }
        .coordinateSpace(name: "scroll")
        .task(id: size) {
            guard size != .zero else { return }
            loadImage(width: size.width, height: size.height * 0.56) // 👈
        }
        .onChange(of: item.unwrappedImageData) { newImageData in
            updateImage(data: newImageData, width: size.width, height: size.height * 0.56)
        }
        .onDisappear {
            uiImage = nil
        }
    }
    
    @ViewBuilder
    private var imageHeaderView: some View {
        let imageHeight = size.height * 0.56
        
        GeometryReader { proxy in
            let size = proxy.size
            let minY = proxy.frame(in: .named("scroll")).minY
            let opacityProgress = (minY / imageHeight) * 1.52
            
            Group {
                if !item.unwrappedImageData.isEmpty, let image = uiImage {
                    Image(uiImage: image)
                        .resizable()
                        .aspectRatio(contentMode: .fill)
                        .frame(width: size.width, height: size.height + (minY > 0 ? minY : 0), alignment: .top)
                        .clipped()
                } else {
                    Image(systemName: "tshirt.fill")
                        .font(.largeTitle)
                        .imageScale(.large)
                        .fontWeight(.regular)
                        .foregroundColor(.secondary.opacity(0.55))
                        .frame(width: size.width, height: size.height + (minY > 0 ? minY : 0))
                        .background(Color.customSecondBackgroundColor)
                }
            }
    }
    
    private func loadImage(width: CGFloat, height: CGFloat) {
        guard !item.unwrappedImageData.isEmpty else { return }
// 👈
        uiImage = downsampleImage(imageData: item.unwrappedImageData,
                                  to: CGSize(width: width, height: height))
    }
    
    private func updateImage(data: Data, width: CGFloat, height: CGFloat) {
        uiImage = !data.isEmpty ? downsampleImage(imageData: data, to: CGSize(width: width, height: height)) : nil
    }
    
    private func downsampleImage(imageData: Data, to pointSize: CGSize, scale: CGFloat = UIScreen.main.scale) -> UIImage {
        let imageSourceOptions = [kCGImageSourceShouldCache: false] as CFDictionary
        guard let imageSource = CGImageSourceCreateWithData(imageData as CFData, imageSourceOptions) else { return UIImage() }
        
        let maxDimensionInPixels = max(pointSize.width, pointSize.height) * scale
        let downsampleOptions = [
            kCGImageSourceCreateThumbnailFromImageAlways: true,
            kCGImageSourceShouldCacheImmediately: true,
            kCGImageSourceCreateThumbnailWithTransform: true,
            kCGImageSourceThumbnailMaxPixelSize: maxDimensionInPixels
        ] as CFDictionary
        
        guard let downsampledImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, downsampleOptions) else { return UIImage() }
        return UIImage(cgImage: downsampledImage)
    }
}
异步 SwiftUI 同步 缩减采样 loadimage

评论

0赞 Timmy 7/29/2023
我专门为此写了一个包:github.com/TimmysApp/MediaUI

答: 暂无答案