SwiftUI

SwiftUI GeometryReader用法

苹果官方定义:A container view that defines its content as a function of its own size and coordinate space.

GeometryReader is a view that gives you access to the size and position of your parent.

SwiftUI布局的核心原理是什么呢? 主要分3个步骤:
    • 父view提供一个建议的size
    • 子view根据自身的特性返回一个size
    • 父view使用子view返回的size对子view进行布局

GeometryReader的基本用法就是读取父View建议的大小, 然后使用它来布局我们的View。
    • GeometryReader一个容器View
    • 可以自己决定内容的大小与位置


例子1: 在一个 VStack 中垂直摆放两个元素 Text 和 MyRectangle, 
其中 MyRectangle 的大小为父容器 VStack显示完Text后剩余空间的1/3。
struct ContentView: View {
    var body: some View {
        VStack {
            Text("下面是一个矩形")
            MyRectangle()
        }.frame(width: 150, height: 100) .border(Color.black)
    }
}
struct MyRectangle: View {
    var body: some View {
         //  GeometryReader是去掉Text view之后, 剩余之后的view。
         GeometryReader { geometry in
            Rectangle()
                .foregroundColor(Color.blue)
                 // 通过geometry可以取得父view的大小(去掉Text view剩余之后的大小)。
                .frame(width: geometry.size.width * 0.3, height: geometry.size.height * 0.3, alignment: .center)
        }
    }
}
例子2:
通过GeometryProxy可以拿到父容器布局的相关信息,这个是它能做到自己决定内容的大小与位置的核心,主要作用如下:
可以通过size: CGSize获取宽和高。
可以通过safeAreaInsets获取安全区域相关的信息。
可以通过frame()获取屏幕坐标系的 x 和 y 坐标。
struct ContentView: View {
    
    var body: some View {
        ScrollView {
            ZStack {
                VStack {
                    RoundedRectangle(cornerRadius: 20)
                        .foregroundColor(Color.green)
                        .frame(width: 300, height: 300)
                    
                    RoundedRectangle(cornerRadius: 20)
                        .foregroundColor(Color.red)
                        .frame(width: 300, height: 300)
                    
                    RoundedRectangle(cornerRadius: 20)
                        .foregroundColor(Color.purple)
                        .frame(width: 300, height: 300)
                    
                }
                
                GeometryReader { geometry in
                    VStack {
                        // 尺寸
                        Text("Geometry width: \(geometry.size.width)")
                        Text("Geometry height: \(geometry.size.height)")
                        
                        // 坐标
                        Text("Geometry X: \(geometry.frame(in: .global).origin.x)")
                        Text("Geometry Y: \(geometry.frame(in: .global).origin.y)")
                        Text("Geometry minX: \(geometry.frame(in: .global).minX)")
                        Text("Geometry maxX: \(geometry.frame(in: .global).maxX)")
                        
                        // 安全区域
                        Text("Geometry safeAreaInsets.bottom: \(geometry.safeAreaInsets.bottom)")
                        Text("Geometry safeAreaInsets.top: \(geometry.safeAreaInsets.top)")
                    }
                }
            }
        }.edgesIgnoringSafeArea(.all) // 观察有无此句的内容变化
    }
}