2021-06-22

SwiftUI 简明教程之 GeometryReader、PreferenceKey

本文为 Eul 样章,如果您喜欢,请移步 AppStore/Eul 查看更多内容。

Eul 是一款 SwiftUI & Combine 教程 App(iOS、macOS),以文章(文字、图片、代码)配合真机示例(Xcode 12+、iOS 14+,macOS 11+)的形式呈现给读者。笔者意在尽可能使用简洁明了的语言阐述 SwiftUI & Combine 相关的知识,使读者能快速掌握并在 iOS 开发中实践。

GeometryReader

GeometryReader 是一个通过闭包来构建视图的容器,可以返回一个 GeometryProxy 类型的结构体,它包含如下属性和方法,由此我们可以获取当前视图容器(即父视图)的尺寸和位置,绘制以其为参考坐标系的视图。

var safeAreaInsets: EdgeInsets// The safe area inset of the container view.var size: CGSize// The size of the container view.func frame(in: CoordinateSpace) -> CGRect// Returns the container view's bounds rectangle, converted to a defined coordinate space.

比如,我们需要绘制一个长宽均为父视图一半的矩形:

struct ContentView: View { var body: some View { GeometryReader { gr in  RoundedRectangle(cornerRadius: 10)  .fill(Color.blue)  .frame(width: gr.size.width * 0.5, height: gr.size.height * 0.5)  .position(x: gr.frame(in: .local).midX, y: gr.frame(in: .local).midY) } }}

我们再来看看 GeometryProxy 包含的实例方法:func frame(in: CoordinateSpace) -> CGRect,这里的 CoordinateSpace 是个枚举类型,有以下几种情况:

case global // 参考系为屏幕case local // 参考系为父视图case named(AnyHashable) // 参考系为自定义

通过这个方法,我们可以获取到当前视图在不同参考系中的位置和尺寸,我们将代码改成如下:

struct ContentView: View { var body: some View { VStack(spacing: 10) {  text("Top", width: 100, height: 50)   HStack(spacing: 10) {  text("Left", width: 50, height: 100)  roundRect   .background(Color.black)  text("Right", width: 50, height: 100)  }   text("Bottom", width: 100, height: 50) } .coordinateSpace(name: "VStack") } var roundRect: some View { GeometryReader { gr in  RoundedRectangle(cornerRadius: 10)  .fill(Color.blue)  .frame(width: gr.size.width * 0.5, height: gr.size.height * 0.5)  .position(x: gr.frame(in: .local).midX, y: gr.frame(in: .local).midY)  .onTapGesture {   print("screen: \(UIScreen.main.bounds)")   print("global: \(gr.frame(in: .global))")   print("local: \(gr.frame(in: .local))")   print("custom: \(gr.frame(in: .named("VStack")))")  } } } func text(_ text: String, width: CGFloat, height: CGFloat) -> some View { Text(text)  .frame(width: width, height: height)  .background(Color.orange)  .cornerRadius(10) }}

运行模拟器 iPhone 12 Pro(safeAreaInsets: 47.0, 0.0, 34.0, 0.0),点击蓝色区域,控制台打印如下结果:

screen: (0.0, 0.0, 375.0, 812.0)global: (60.0, 148.0, 255.0, 570.0)local: (0.0, 0.0, 255.0, 570.0)custom: (60.0, 60.0, 255.0, 570.0)

这与我们之前所说的枚举类型对应的坐标参考系是一致的。

PreferenceKey

还记得我们在前面的"自定义对齐方式"中讲过的,如何对齐手机和电子邮箱的例子吗?其实,我们还有另外一种思路来实现类似的效果,那就是获取文字列所有的内容的宽度,取最大值,重绘界面即可。那么问题来了,如何获取这个最大值呢?答案就是 PreferenceKey,它可以收集视图树中子视图的数据,回传给父视图(跨层级亦可)。这里我们需要获取尺寸,还用到了 GeometryReader。

struct ContentView : View { @State private var email = "" @State private var password = "" // 保存、更新文字列所需要的合适宽度,这里是最大值 @State private var textWidth: CGFloat? var body: some View { Form {  HStack {  Text("电子邮箱")   .frame(width: textWidth, alignment: .leading)   .background(TextBackgroundView())  TextField("请输入", text: $email)   .textFieldStyle(RoundedBorderTextFieldStyle())  }   HStack {  Text("密码")   .frame(width: textWidth, alignment: .leading)   .background(TextBackgroundView())  TextField("请输入", text: $email)   .textFieldStyle(RoundedBorderTextFieldStyle())  } } .onPreferenceChange(TextWidthPreferenceKey.self) { (value) in  print(value)  textWidth = value.max() } }}struct TextBackgroundView: View { var body: some View { GeometryReader { gr in  Rectangle()  .fill(Color.clear)  .preference(key: TextWidthPreferenceKey.self,     value......

原文转载:http://www.shaoqun.com/a/819665.html

跨境电商:https://www.ikjzd.com/

adore:https://www.ikjzd.com/w/2202

塔图:https://www.ikjzd.com/w/2274

刘小东:https://www.ikjzd.com/w/1853


本文为Eul样章,如果您喜欢,请移步AppStore/Eul查看更多内容。Eul是一款SwiftUI&Combine教程App(iOS、macOS),以文章(文字、图片、代码)配合真机示例(Xcode12+、iOS14+,macOS11+)的形式呈现给读者。笔者意在尽可能使用简洁明了的语言阐述SwiftUI&Combine相关的知识,使读者能快速掌握并在iOS开发中实践。Geome
noon:https://www.ikjzd.com/w/259
Milk Stork:https://www.ikjzd.com/w/2496
女人3大绝招 让老公乖乖听话女人绝招老公:http://lady.shaoqun.com/m/a/38224.html
深圳西涌沙滩可以烧烤吗:http://www.30bags.com/a/447903.html
中港星海外企业服务中心:https://www.ikjzd.com/w/2494
Move Loot:https://www.ikjzd.com/w/2495
南部千年盐都 最美精彩自贡:http://www.30bags.com/a/415725.html
情人节应该在哪儿求婚蛙步告诉您 :http://www.30bags.com/a/409131.html
老师让我脱她乳罩摸她乳 老师的胸软软的真好吃:http://lady.shaoqun.com/a/247803.html
你太大了岳你太紧疼了 岳两腿中间流水了:http://lady.shaoqun.com/m/a/248077.html
深圳大梅沙需要核酸检测阴性证明吗:http://www.30bags.com/a/447901.html
深圳中英街需要核酸检测阴性证明吗:http://www.30bags.com/a/447902.html

No comments:

Post a Comment