第94天 项目 18 第三部分
你准备好完成我们最后的技巧项目了吗?希望你已经准备好了,因为你还有一次复习要完成,另外还有三个新的挑战等着你。现在我要提醒你:这些挑战都涉及GeometryReader,因为它会迫使你清晰地思考每个视图的框架是如何计算的,以及如何利用这些框架创造出有趣的效果。
我知道GeometryReader确实可能让你感到困惑,但要想熟练掌握它——有效地使用它,唯一的方法就是不断练习、练习、再练习。
我之前引用过艾米·莫林的话,今天我想最后再引用一次。她说:“生活中最美好的事情往往发生在我们的舒适区之外,而怀疑自己走出舒适区的能力会让你停滞不前。”所以,就从今天开始,走出你的舒适区,让GeometryReader听从你的“指挥”吧!
今天你需要完成项目18的总结章节,完成相关复习,然后攻克所有三个挑战。
- 布局与几何:总结
- 项目18复习:布局与几何
布局与几何:总结
作者:Paul Hudson 2024年2月21日
希望这个规模较小的技巧项目能让你在完成那些冗长的应用项目后得到一个愉快的调剂,但我更希望你现在已经开始对SwiftUI的布局系统有一个清晰的认知模型了。这个三步式的布局系统听起来可能很简单,但要完全理解它所带来的影响还需要时间。
至于GeometryReader,它属于那种你完全可以不用考虑也能应付日常开发的工具,这没什么问题。但有时候——只是有时候——你需要一些额外的功能,而这些功能是容器相对框架或其他SwiftUI选项无法提供的,这时候GeometryReader就能派上用场了。
回顾所学内容
任何人都能看完一个教程,但要记住所学的知识还需要实际付出努力。确保你能从这些教程中收获尽可能多的知识是我的职责,完成后面的练习题可以帮助你检验自己的学习成果。
挑战
学习编程最好的方法之一就是尽可能多地自己编写代码,所以我为你准备了三个挑战,让你通过实践来巩固对GeometryReader的理解。
首先,将你的ContentView恢复到我们之前做过的旋转彩色行示例:
struct ContentView: View {
let colors: [Color] = [.red, .green, .blue, .orange, .pink, .purple, .yellow]
var body: some View {
GeometryReader { fullView in
ScrollView(.vertical) {
ForEach(0..<50) { index in
GeometryReader { proxy in
Text("第\(index)行")
.font(.title)
.frame(maxWidth: .infinity)
.background(colors[index % 7])
.rotation3DEffect(.degrees((proxy.frame(in: .global).minY - fullView.size.height / 2) / 5), axis: (x: 0, y: 1, z: 0))
}
.frame(height: 40)
}
}
}
}
}完成上述操作后:
- 让滚动视图顶部附近的视图淡出至透明度为0——建议从顶部约200点的位置开始。
- 让视图根据其垂直位置调整缩放比例,底部附近的视图较大,顶部附近的视图较小。建议最小缩放比例不低于正常大小的50%。
- 作为一个更高难度的挑战,让视图在滚动时改变颜色。为了达到最佳效果,你应该使用
Color(hue:saturation:brightness:)初始化器来创建颜色,并为色调(hue)传入不同的值。
要找到合适的数值,每一项挑战都需要你进行一些尝试和调整。无论如何,在缩放时你应该使用max()函数,确保视图不会缩小到正常大小的一半以下;在处理色调时使用min()函数,确保色调值不会超过1.0。
布局与几何
问题1/12:以下哪些陈述是正确的?
- 选项1:SwiftUI使用三步式布局流程。
- 选项2:
GeometryReader总是会占据其父视图提供的所有可用空间。
问题2/12:以下哪些陈述是正确的?
- 选项1:创建自定义对齐指南时,我们必须提供默认值。
- 选项2:SwiftUI有五个内置的坐标空间。
问题3/12:以下哪些陈述是正确的?
- 选项1:如果我们编写
Text("Hello, World!").background(.red),那么文本视图是背景视图的子视图。 - 选项2:如果我们编写
Text("Hello, World!").background(.red),那么背景视图是文本视图的子视图。
问题4/12:以下哪些陈述是正确的?
- 选项1:
Color视图是布局中立的(layout neutral)。 - 选项2:父视图可以强制其子视图采用特定的大小。
问题5/12:以下哪些陈述是正确的?
- 选项1:在
HStack中,我们可以使用第一个或最后一个文本视图的基线来对齐文本。 - 选项2:子视图必须始终使用小于或等于父视图提供的空间。
问题6/12:以下哪些陈述是正确的?
- 选项1:SwiftUI将视图的位置和大小存储为整数。
- 选项2:
offset()修饰符会改变视图的渲染位置,但不会实际改变其原始尺寸。
问题7/12:以下哪些陈述是正确的?
- 选项1:文本的基线(baseline)是字母最低处的正下方。
- 选项2:视图的大小始终与其主体(body)的大小完全相同。
问题8/12:以下哪些陈述是正确的?
- 选项1:
GeometryReader在其布局闭包中会提供一个值,该值是一个包含布局信息的GeometryProxy。 - 选项2:除非我们指定自定义对齐方式,否则大多数父视图总会将其子视图放置在可用空间的左上角。
问题9/12:以下哪些陈述是正确的?
- 选项1:文本视图会自动调整大小以适应显示所有文本行所需的空间。
- 选项2:创建自定义对齐指南是个糟糕的主意。
问题10/12:以下哪些陈述是正确的?
- 选项1:
GeometryReader会告诉我们父视图提议的大小。 - 选项2:
createCoordinate()修饰符可以让我们创建自定义坐标空间。
问题11/12:以下哪些陈述是正确的?
- 选项1:
alignmentGuide()修饰符允许我们编写自定义代码来计算视图的对齐指南。 - 选项2:在SwiftUI中无法绝对定位视图。
问题12/12:以下哪些陈述是正确的?
- 选项1:
GeometryReader提供的框架(frame)会在视图移动时自动更新。 - 选项2:创建自定义对齐指南时,建议使用结构体(struct)而非枚举(enum)。