如果非要把GeometryReader 翻译成中文,根据我个人的理解可以翻译为:几何及坐标读取者(几何参数读取),GeometryReader主要用于获取父视图的大小和位置,从而让子视图可以随父视图的大小变化而灵活变化其形态和内容,它的输入类型为 (GeometryProxy) -> Content,下面代码里的 GeometryProxy(也就是这里的 proxy),它是一个返回访问容器视图的大小和坐标空间(用于锚点解析)的代理。其有 2 个属性(safe
GeometryProxy属性1:var safe
GeometryProxy属性2:var size: CGSize 容器视图的大小。
GeometryProxy方法:func frame(in: Coordinate
其方法中的 CoordinateSpace 是一个枚举值:global、local、named(Any
SwiftUI布局3大法则
1. 父级Vew为子级的View提供一个建议尺寸值(size)
2. 子级的View根据这个建议的尺寸(size)和自身的特点返回一个尺寸值(size)
3. 父级View根据子级View返回的尺寸值(size)在坐标空间中布局。
而GeometryReader的作用就是:
1. 能够获取到父级View给出的建议的尺寸值(size)
2. 可以通过frame(in:)函数,传入一个相对坐标系,可以获取GeometryReader相对某个view的frame
3. 在某些特殊情况下,比如ScrollView中加了GeometryReader,如果使用了frame(in:)函数,返回的值会根据view的位置实时的自动变化,利用此技术可以实现复杂UI功能(这里有演示代码:http://www.55mx.com/ios/115.html)。
var body: some View {
Rectangle()
.stroke(lineWidth: 5)
.frame(width: 200, height: 200, alignment: .center)
.overlay(subView)//用subView子视图覆盖在本视图之上
}
//定义一个subView子视图
var subView: some View {
GeometryReader { proxy in
Rectangle()//定义一个矩形
.foregroundColor(.blue)//设置颜色
//定义矩形的大小为父视图的一半
.frame(width: proxy.size.width / 2, height: proxy.size.height / 2)
//让矩形根据坐标偏移
.offset(x: proxy.size.width / 2.3,y: proxy.size.height / 9)
}
}
GeometryProxy 的另一个属性是 safeAreaInsets, 用来表示当前不可用的空间有多少。例如 safeAreaInsets.top 表示了上方刘海部分加上导航栏的高度safeAreaInsets.bottom 表示下方圆角部分的高度。
GeometryReader { proxy in
List {
Text("在模拟器中翻转屏幕,来观察 4 条边上”安全区域“的数值变化").bold()
Text("安全区域.顶: (proxy.safeAreaInsets.top)")
Text("安全区域.底: (proxy.safeAreaInsets.bottom)")
Text("安全区域.左: (proxy.safeAreaInsets.leading)")
Text("安全区域.右: (proxy.safeAreaInsets.trailing)")
}
}
除了上述的属性,GeometryProxy 还有 frame 这个方法会返回一个 CGRect,可以用来获取父视图相对某一坐标的位置。下面的例子中 .local 获得的就是相对父视图的坐标系,所以 x, y 都是 0,红色方块和黑框重叠而.global 就是父视图相对整体的位置,所以蓝方块也向右下进行了平移。
GeometryReader { geometry in
ZStack {
Rectangle()
//path将此形状描述为矩形参照系内的路径。
.path(in: geometry.frame(in: .local))
//校正描述这个形状的参考系为相对父视图的坐标系。
.foregroundColor(.red)
Rectangle()
//参考系为父视图相对整体的位置。
.path(in: geometry.frame(in: .global))
.foregroundColor(.blue)
}
}
ScrollView(.horizontal){
HStack{
ForEach(0..<50){ i in
GeometryReader{ proxy in
let x = Int(proxy.frame(in:.global).origin.x)//全局的x坐标位置
Text("X:(x)")//当滚动视图时X值会随之改变
.bold()
.font(.largeTitle)
.foregroundColor(.white)
//大概会偏移到中间位置
.offset(x: proxy.size.width / 3, y: proxy.size.height / 3)
}
.frame(width: 200, height: 200)
.background(Color.orange)
.padding()
}
}
}
如果在上面的Text视图后面加上下面的代码就变成了跳舞的文字:
.rotation3DEffect(.degrees(-Double(proxy.frame(in:.global).minX)),axis: (x:0, y:1, z:0))
首先定义一批颜色演示:
let colors: [Color] = [.red, .green, .blue, .orange, .pink, .purple, .yellow]
然后在视图里使用下面的代码:
GeometryReader { fullView in
ScrollView(.horizontal, showsIndicators: false) {
HStack {
ForEach(0..<50) { index in
GeometryReader { geo in
Rectangle()
.fill(colors[index % colors.count])
//用颜色或渐变填充这个形状。
.frame(height: 150)
//下面的算法是效果的关键
.rotation3DEffect(.degrees(-Double(geo.frame(in: .global).midX - fullView.size.width / 2) / 10), axis: (x: 0, y: 1, z: 0))
}
.frame(width: 150)
}
}
.padding(.horizontal, (fullView.size.width - 150) / 2)
}
}
如果要在VStack里应用螺旋样式的旋转效果,请将其rotation3DEffect()直接放在修改器下方:
.rotation3DEffect(.degrees(Double(geo.frame(in: .global).minY) / 5), axis: (x: 0, y: 1, z: 0))
当我们Image在SwiftUI中创建视图时,它将根据其内容的尺寸自动调整自身大小。因此,如果图片为1000x500,则Image视图也将为1000x500。有时您将希望以较小的尺寸显示图像,以及如何使用以下方法使图像适合用户的屏幕宽度:
GeometryReader { geo in
Image(systemName: "calendar.circle.fill")
.resizable()
.aspectRatio(contentMode: .fit)
//利用GeometryProxy读取容器大小并填充满
.frame(width: geo.size.width, height: geo.size.height)
}
GeometryReader与我们使用过的其他视图一样,当它在创建视图时,我们将获得一个GeometryProxy(上面代码里的geo)对象。这使我们可以查询当前视图的环境信息:比如容器有多大?我们的位置(x、y)是什么?是否有安全区域等信息。
除非注明,网络人的文章均为原创,转载请以链接形式标明本文地址:https://www.55mx.com/post/117
《【SwiftUI基础篇】3 GeometryReader的用法详解》的网友评论(0)