提问人:idhun90 提问时间:7/29/2023 更新时间:7/29/2023 访问量:34
我应该如何在 SwiftUI 中实现缩减采样和加载图像:同步还是异步?
How should I implement downsampling and loading images in SwiftUI: synchronously or asynchronously?
问:
我需要对存储在 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)
}
}
答: 暂无答案
评论