为什么.task修饰符中GeometryReader的闭包参数的第一个大小的值为0,如何修复它?

问题描述 投票:0回答:0

我正在创建一个应用程序,它在主屏幕上显示项目列表,并在详细视图中显示所选项目的图像和详细信息。

为了尽量减少图像的内存占用,我在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
        }

对吗???

swiftui task size geometryreader
© www.soinside.com 2019 - 2024. All rights reserved.