GeometryReader 坐标空间返回错误的框架

Kex*_*Kex 1 ios swift swiftui geometryreader

我在使用几何阅读器时遇到问题coordinateSpace,我已将问题简化为演示:

struct AddTransaction: View {

    // MARK: - Views

    var body: some View {
        NavigationView {
            GeometryReader { reader in
                VStack {
                    Spacer()

                    Button("Height") {
                        print("\(reader.frame(in: .named("rectangle")).height)")
                    }
                    Rectangle()
                        .frame(height: 200.0)
                        .coordinateSpace(name: "rectangle")

                }
                .navigationTitle("Demo")
                .navigationBarTitleDisplayMode(.inline)
            }
            .ignoresSafeArea(.keyboard)
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

我需要在我的实际项目中使用,coordinateSpace因为布局更复杂,我无法使用global.

当我按下按钮时,高度报告为 697.0(整个屏幕),而不是预期的 200.0。我在这里做错了什么?

ahe*_*eze 5

您的代码中的一些内容似乎不对。首先,看起来您正在尝试使用coordinateSpace“标记”矩形来获取其框架。这不是文档中 \xe2\x80\x94 的修饰符:

\n
\n

为 view\xe2\x80\x99s 坐标空间分配一个名称,以便其他代码可以对相对于命名空间的点和大小等维度进行操作。

\n
\n

所以coordinateSpace修改器实际上是创建一个新的坐标空间,原点移了过来。在此示例中,yellow坐标空间的原点位于黄色矩形的左上角。

\n
struct ContentView: View {\n    var body: some View {\n        VStack {\n            Color.green\n\n            Color.yellow\n                .overlay {\n                    GeometryReader { reader in\n                        \n                        /// The frame of the `GeometryReader` relative to the `yellow` container.\n                        let frame = reader.frame(in: .named("yellow"))\n                        Text(verbatim: "Frame: \\(frame)")\n                    }\n                    .frame(width: 300, height: 50)\n                    .border(.red)\n                }\n                .coordinateSpace(name: "yellow")\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n文本覆盖在正方形上\n

另一件事是它GeometryReader会扩展以填满所有可用空间,以及您从您的框架中获得的框架reader实际上是整个几何读取器 \xe2\x80\x94 的框架,而不仅仅是黑色矩形。

\n

您可以尝试将几何阅读器作为backgroundoverlay放在矩形上,这样它就不会扩展它。

\n
struct AddTransaction: View {\n    @State var frame = CGRect.zero\n\n    // MARK: - Views\n\n    var body: some View {\n        NavigationView {\n            VStack {\n                Spacer()\n\n                Button("Height") {\n                    print("\\(frame.height)")\n                }\n\n                Rectangle()\n                    .frame(height: 200.0)\n                    .frameReader { frame in\n                        self.frame = frame\n                    }\n\n                    .navigationTitle("Demo")\n                    .navigationBarTitleDisplayMode(.inline)\n            }\n            .ignoresSafeArea(.keyboard)\n        }\n    }\n}\n\npublic extension View {\n    /// Read a view\'s frame. From /sf/answers/4677572301/\n    func frameReader(in coordinateSpace: CoordinateSpace = .global, rect: @escaping (CGRect) -> Void) -> some View {\n        return background(\n            GeometryReader { geometry in\n                let frame = geometry.frame(in: coordinateSpace)\n\n                Color.clear\n                    .preference(key: ContentFrameReaderPreferenceKey.self, value: frame)\n                    .onPreferenceChange(ContentFrameReaderPreferenceKey.self) { newValue in\n\n                        DispatchQueue.main.async {\n                            rect(newValue)\n                        }\n                    }\n            }\n        )\n    }\n}\n\nstruct ContentFrameReaderPreferenceKey: PreferenceKey {\n    static var defaultValue: CGRect { return CGRect() }\n    static func reduce(value: inout CGRect, nextValue: () -> CGRect) { value = nextValue() }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

请注意,这不是最佳方法 \xe2\x80\x94 最好将框架详细信息留给 SwiftUI 并尽可能避免使用 GeometryReader。如果您支持iOS 16,可以尝试使用新的布局协议。

\n