最近在开发 瓦尔登 UI2.0 的笔记模块,这里记录一下遇到的问题和解决方案

问题:为什么在 Form 中使用 GeometryReader 时无法正确显示高度?

我们通常使用 GeometryReader 来获取 Container View 的尺寸,这在大多数情况下是可以正常使用的。但如果我们在 Form 中(或者 List、Scrollview 这类可滚动的 View)用到 GeometryReader 的同时又用到了 Lazy View,情况就会有点复杂,因为这类 View 的尺寸是动态变化的,导致的结果就是 View 的高度显示不正确(Form 表单的默认高度),如下图所示。

GeometryReader { proxy in
    let width = proxy.size.width
    let imageW = (width - 2 * 5) / 3
    LazyVGrid(columns: noteImageCols, content: {
        ForEach(note.imageArray) { image in
            ImageView(image: image)
                .frame(width: imageW, height: imageW)
        }
    })
}

可以看到,图片并没有显示完整(实际上有 4 张图)

解决方案:获取动态布局的尺寸

能否在 GeometryReader 获取高度来设定呢?答案是不行的

GeometryReader { proxy in
    let width = proxy.size.width
    let height = proxy.size.height // 这样是不行的 ❌
    let imageW = (width - 2 * 5) / 3
    LazyVGrid(columns: noteImageCols, content: {
        ForEach(note.imageArray) { image in
            ImageView(image: image)
                .frame(width: imageW, height: imageW)
        }
    })
    .frame(height: height) // 这样是不行的 ❌
}

但我们可以通过 LazyVGrid 的 background 这个 modifier 来获取真实的高度值,代码和效果如下

@State private var realHeight: CGFloat = 0 // 这样 OK ✅
GeometryReader { proxy in
    let width = proxy.size.width
    // let height = proxy.size.height // 这样是不行的 ❌
    let imageW = (width - 2 * 5) / 3
    LazyVGrid(columns: noteImageCols, content: {
        ForEach(note.imageArray) { image in
            ImageView(image: image)
                .frame(width: imageW, height: imageW)
        }
    })
    .background( GeometryReader { proxy2 -> Color in
        let height = proxy2.size.height
        realHeight = height
        return .clear 
    }) // 这样 OK ✅
    //.frame(height: height) // 这样是不行的 ❌
}
.frame(height: realHeight)  // 这样 OK ✅

为什么通过 background 就能够获取正确的高度呢?因为 background 的尺寸大小是会着 View 的变化而变化的,因此在里面套一层 GeometryReader 就能够获得动态变化的尺寸大小

Categorized in:

Tagged in:

, ,