我正在创建一个应用程序,它在主屏幕上显示项目列表,并在详细视图中显示所选项目的图像和详细信息。
为了尽量减少图像的内存占用,我在DetailView的.task修饰符中对GeometryReader的闭包参数的size值进行降采样,但是第一次获取size值时,宽度和高度值都是0 ,所以看不到图像。
当我调试它时,我看到我得到了第一个0值,然后是正确的值,所以我确认图像通过.task(id: size)修饰符可见,但我不确定这是否是正确的做法。
如果您能告诉我为什么我一开始得到的 size.width、size.height 值都是 0,以及我所做的是否是正确的方法,以及我是否应该始终下采样,我将不胜感激图像?
struct ContextView: View {
@State private var seletedItem: Item?
var body: some View {
MainListView()
.sheet(item: $seletedItem) { item in
GeometryProxy { proxy in
let size = proxy.size // 👈
DetailImageView(item: item, size: size)
.ignoresSafeArea(.container, edges: .top)
}
}
}
}
struct DetailImageView: View {
var item: Item
var size: CGSize
@State private var uiImage: UIImage? = nil
var body: some View {
ScrollView {
GeometryReader { proxy in
let childSize = proxy.size
if let uiImage {
Image(uiImage: uiImage)
.resizable()
.scaledToFill()
.frame(width: childSize.width, height: childSize.height)
}
}
.frame(height: size.height)
}
.coordinateSpace(name: "scroll")
.task {
// ❌ not show Image, not working 👈
// size.width = 0, size.height = 0
uiImage = downsampleImage(imageData: item.imageData,
to: CGSize(width: size.width, height: size.height))
}
.task(id: size) {
// ✅ show Image, working 👈
uiImage = downsampleImage(imageData: item.imageData,
to: CGSize(width: size.width, height: size.height))
}
}
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)
}
}
我使用 .task(id: size) 修饰符在大小更改时重新绘制 body 属性
+++++
@State private var isSizeZero = true
...
if isSizeZero {
ProgressView()
} else {
if let uiImage {
Image(uiImage: uiImage)
.resizable()
.scaledToFill()
}
}
.frame(width: childSize.width, height: childSize.height)
...
.task(id: size) {
if size == 0 {
isSizeZero = true
return
} else {
uiImage = downsampleImage(imageData: item.imageData,
to: CGSize(width: size.width, height: size.height))
isSizeZero = false
}
对吗???