SwiftUI 佈局: Alignment & AlignmentGuides

\color{red}{\Large \mathbf{Hacking \quad with \quad iOS: SwiftUI \quad Edition}}

{\Large \mathbf{Alignment \ and \ Alignment \ Guides}}

SwiftUI 爲我們提供了許多有價值的方法來控制視圖的對齊方式,我將逐一介紹這些方法,以便您可以看到它們的實際操作。

  • 最簡單的對齊選項是使用frame()修飾符的alignment參數。

請記住,文本視圖總是使用顯示其文本所需的精確寬度和高度,但是當我們在其周圍放置邊框時,它可以是任何大小。由於父對象對子對象的最終大小沒有發言權,因此這樣的代碼將創建一個300x300的框架,並在其內部以較小的文本視圖爲中心:

Text("Live long and prosper")
    .frame(width: 300, height: 300)

如果不希望文本居中,請使用frame()alignment參數。例如,當在從左到右的環境中運行時,此代碼將視圖放在左上角

    .frame(width: 300, height: 300, alignment: .topLeading)

然後可以使用offset(x:y:)在 frame 內移動文本。

  • 下一個選項是使用堆棧的對齊參數。

例如,這裏有四個大小不同的文本視圖排列在HStack中:

HStack {
    Text("Live")
        .font(.caption)
    Text("long")
    Text("and")
        .font(.title)
    Text("prosper")
        .font(.largeTitle)
}

我們沒有指定對齊方式,因此默認情況下它們將居中。這看起來不太好,所以您可能會考慮將它們全部對齊到一個邊,以獲得更整潔的線條,如下所示:

HStack(alignment: .bottom) {

然而,這看起來也很糟糕:因爲每個文本視圖的大小不同,它們也有不同的基線——這就是“abcde”之類的字母在一行上的名稱,這不包括行下方的字母,如“gjpy”。因此,小文本的底部低於較大文本的底部。

幸運的是,SwiftUI有兩個特殊的對齊方式,可以在第一個子級或最後一個子級的基線上對齊文本。這將導致堆棧中的所有視圖在一個統一基線上對齊,而不管它們的字體是什麼:

HStack(alignment: .lastTextBaseline) {

接下來,爲了實現更細粒度的控制,我們可以爲每個單獨的視圖定製“對齊”的含義。爲了更好地瞭解這是如何工作的,我們將從以下代碼開始:

struct ContentView: View {
    var body: some View {
        VStack(alignment: .leading) {
            Text("Hello, world!")
            Text("This is a longer line of text")
        }
        .background(Color.red)
        .frame(width: 400, height: 400)
        .background(Color.blue)
    }
}

運行時,您將看到VStack緊緊圍繞着兩個文本視圖,背景爲紅色。兩個文本視圖的長度不同,但由於我們使用了.leading對齊方式,因此在從左到右的環境中,它們都將與它們的左邊緣對齊。除此之外還有一個藍色背景的大框架。因爲frame大於VStack,所以以VStack中間爲中心。

現在,當VStack開始對齊這些文本視圖時,它要求它們提供它們的 leading。默認情況下,這很明顯:它使用視圖的左邊緣或右邊緣,具體取決於系統語言。但是如果我們想改變這一點呢?如果我們想讓一個視圖具有自定義對齊方式呢?

SwiftUI爲此提供了alignmentGuide()修飾符。這需要兩個參數:我們要更改的指南和返回新對齊方式的閉包。閉包被賦予一個ViewDimensions對象,該對象包含其視圖的寬度和高度,以及讀取其各種邊的能力。

默認情況下,視圖的.leading對齊嚮導是其.alignmentGuide(.leading)——我知道這聽起來很明顯,但實際上它相當於:

VStack(alignment: .leading) {
    Text("Hello, world!")
        .alignmentGuide(.leading) { d in d[.leading] }
    Text("This is a longer line of text")
}

我們可以重寫該對齊嚮導,以使用視圖的 trailing 作爲其leading gaide 對齊嚮導,如下所示:

VStack(alignment: .leading) {
    Text("Hello, world!")
        .alignmentGuide(.leading) { d in d[.trailing] }
    Text("This is a longer line of text")
}


現在您將看到我爲什麼要添加顏色:第一個文本視圖將向左移動,以便它的右邊緣位於下面視圖的左邊緣的正上方,VStack將展開以包含它,整個內容仍將位於藍色框架的中心。

此結果與使用offset()修飾符不同:如果偏移文本,則其原始尺寸實際上不會更改,即使生成的視圖在不同的位置呈現。如果我們偏移了第一個文本視圖而不是改變它的對齊指南,VStack不會擴展到包含它。

雖然對齊導向閉包已傳遞給視圖的尺寸,但如果不想使用,則不需要使用它們–可以發回硬編碼的編號,或創建其他計算。例如,通過將10個文本視圖的位置乘以-10,可以爲10個文本視圖創建一個分層效果:

var body: some View {
    VStack(alignment: .leading) {
        ForEach(0..<10) { position in
            Text("Number \(position)")
                .alignmentGuide(.leading) { _ in CGFloat(position) * -10 }
        }
    }
    .background(Color.red)
    .frame(width: 400, height: 400)
    .background(Color.blue)
}

要完全控制對齊指南,您需要創建自定義對齊指南。我認爲這本書應該有一個小章節…

Alignment and alignment guides

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章