写在前面
您点进来可能是想要了解SwiftUI中alignmentGuide相关的东西,本文
翻译再创作自swiftui-lab,侵删。
您可以查看英文原版:
https://swiftui-lab.com/alignment-guides/
⚠️:翻译过程中对alignment保持了英语,可以翻译成对齐,目的为了和我们常说的“对齐”区分,alignmentGuide可以翻译成“对齐指导”,这里我也保留了alignmentGuide英语。Container在文章中指的是HStack或者VStack或者ZStack等等类似的容器,也保留了Container原文,View有时也写作视图,无区别,由于csdn的某些问题导致图片可能上传失败,您可以对照英文原文查看,也可以根据我提供的图片链接查看。
正文
AlignmentGuide功能强大,但通常未得到充分利用的布局工具。在许多情况下,它可以帮助我们避免复杂的选择,例如(anchor preferences),正如您所看到的,对齐方式的更改也可以很简单的设置为动画
代码https://gist.github.com/swiftui-lab/c84a9cfd7fd022bcb4a33636ca88d646
但是,如果您尝试使用AlignmentGuide,你可能对结果会感到困惑,它们更趋向于“你期待它们做什么”,除非它们不会。因为目前我们处于SwiftUI的早期阶段,所有有时会你会觉得这只是一个bug,然后就去想别的解决方案。
在花了一些时间测试AlignmentGuide的所里范围之后,我得出了它们的工作方式。但是我同时产生了一些困惑:没有一整套完整有效的方法去面对它。当我们忽略它们的时候,事情就开始变得不顺利了。我整篇文章都想告诉你:“每个Container中的视图都拥有一个alignmentGuide”(EVERY VIEW inside a container, has an alignment guide.)
在本文中,我将尝试消除刚才的困惑,目标明确,出发。代码可以让您直观的看到在对齐过程中发生了什么
看完之后,您应该对AlignmentGuide能做什么不能做什么有了判断力
什么是一个AlignmentGuide
一个AlignmentGuide基于一个数字,它在视图中设置一个点,这个点用来确定如何根据附近的其他视图来约束它自己。可以注意到,alignment可以是垂直的或者是水平的,为了继续阐述这一概念,我们从水平的alignment入手
假设我们有三个视图(A,B和C),它们的水平参考线(guide)是0,20,10。由于参考线的存在,三个视图将被调整至:以A为参考,B和C分别偏移了20和10
同样的,竖直的alignment也是如此[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
根据这个例子,您应该也注意到了这样一个事实:水平alignment需要一根竖线来约束,竖直alignment需要一根水平的线来约束,乍一看很奇怪,但是仔细想想好像确实这么回事儿。
什么是ZStack
稍后我们将使用ZStack,但是您应该知道ZStack同时需要水平和垂直Aligement
疑惑的产生
我认为首先要解决的问题是:您可能在很多地方使用.lead和.training等代码,但是在每种情况下,它们的含义完全不同
别慌,我们将深入研究这些参数中的每一个,这里就是吓唬吓唬你,一会儿您就会感到真相大白。
Container Alignment:他有两个目的,它指明了哪些alignmentGuide是需要忽略的,而哪些是不需要忽略的。但是,他同样为所有没有明确指定alignmentGuide的视图隐式的定义了alignmentGuide(相当于提供默认alignmetGuide?)
Alignment Guide: 除非这个值与ContainerAlignment匹配,否则,这个alignmentGuide在约束(layout)的时候将被忽略
Implicit Alignment Value: 它是一个数值,明确了它所修改的guide的位置,有一些方便的预设值,比如d[.leading], d[.center],等等。但是最终返回的还是一个数字。
Explicit Alignment Value:同样是一个数字值,指明了它所修改guide的位置,这是一个明确的值,也就是您通过编程方式定义的值
Frame Alignment:明确了某个特定的 View Group 中的各个View是如何对齐的
Text Alignment: 对于多行的文本视图,他指定文本行在文本视图内如何对齐
隐式VS显式
容器中的每个视图都拥有一个alignment,着重标记是因为它是最重要的概念之一。我们通过调用.alignmentGuide()来定义对齐方式时,对齐方式是显式的,没有调用的话就是隐式的。隐式对齐的值由容器视图中的alignment参数提供(比如:VStack(alignment: .leading)),稍后我们将看到这些值是什么。
你可能想知道,如果不给VStack,HStack或者ZStack制定对齐参数会发生什么,好吧它们确实有默认值:他们都是.center,很容易记住
ViewDimensions
到目前为止,我们已经看到在alignmentGuide()方法的computeValue闭包中将alignmentGuide应返回一个CGFloat。如果我们没有可用于处理的数据,那么计算这样一个数字可能会比较吃力,还好我们做到了,让我们来研究.alignmentGuide()的方法声明
func alignmentGuide(_ g: HorizontalAlignment, computeValue: @escaping (ViewDimensions) -> CGFloat) -> some View
func alignmentGuide(_ g: VerticalAlignment, computeValue: @escaping (ViewDimensions) -> CGFloat) -> some View
这是一个重写的方法,有两个版本,一个用来水平参考线,一个用来垂直参考线。有意思的是,这种方法为computeValue闭包提供了ViewDimensions类型的参数。这个类型是一个结构体,其中包含一些有关我们要为其创建alignmentGuide的视图有用的信息
public struct ViewDimensions {
public var width: CGFloat {
get } // 视图的宽
public var height: CGFloat {
get } // 视图的高
public subscript(guide: HorizontalAlignment) -> CGFloat {
get }
public subscript(guide: VerticalAlignment) -> CGFloat {
get }
public subscript(explicit guide: HorizontalAlignment) -> CGFloat? {
get }
public subscript(explicit guide: VerticalAlignment) -> CGFloat? {
get }
}
除了两个一眼就能看懂的属性宽和高之外,出现了几个令人费解的下标:它们接收水平Alignment或者竖直Alignment作为他们的索引,让我们来看看如何访问它们
Text("Hello")
.alignmentGuide(HorizontalAlignment.leading, computeValue: