Swift 29 SwiftUIスタック整列 

21章｢SwiftUIストラクトとフレーム」にはスタックコンテナビューで基本的な整列について勉強しました。複雑な使用者インタフェイスレイアウトを設計する時にはSwiftUIスタックビューで提供する標準整列方法以上の方法が必要です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513806/f5fe6558-c755-3d20-7ce7-6ee052e9ff0d.png)
これを念頭に置いて今度の章にはコンテナ整列、整列ガード、カスタム整列、そして異なるスタックの整列実装までスタック整列の高級技術に対して説明しましょう。

# 二十九・壱　コンテナ整列
一番基本的な整列、すたくで含まれた下位ビューがスタック内で整列さる方法を定義します。スタくである各ビューで指定された整列が特になければ、スタックで適用された整列が下位ビューで適用されます。これをimplicity alignedと言います。

整列する時おほえる大事な点はHStackは下位ビューを縦向こうでして、VStackは下位ビューを横向くこでします。ZStackの場合には横・縦関整列値が全て使用されます。

次はVStack宣言は三つの下位ビューを含まれる簡単なVStackで　構成します。
![Screenshot 2023-12-11 at 2.38.24 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513806/005a2581-4434-775b-cab0-39ffc5fa528f.png)
特定コンテーナ整列値がいなければ**VStackは属しているビューは全て「.center」をデフォルトにします。**
VStackは「.leading」「.trailing」を定列に使われることができます。
```diff_swift
VStack(alignment: .trailing) {
            Text("Hello, world!")
            Text("Hello, world!")
            Text("Hello, world!")
        }
```
HStackも基本的に.centerされますが、テキストベイスライン整列ための値だてはなく、上段整列と下段整列も提供します。整列を指定するときスペース値を含まることもできます。次のHStackはデフォルトでスペースがある中央整列を使用して、異なるフォント大きさを持っている三つの下位テキストビューが含まれています。
![Screenshot 2023-12-11 at 2.55.50 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513806/a358a644-39e0-50d2-a082-e859e20dbf64.png)
.textBaseline整列はテキスト基盤ビューのfirstまたはlastを基準することができます。
![Screenshot 2023-12-11 at 3.04.41 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513806/e28a69cf-21d5-baae-5e4b-433ffa654dc0.png)
# 二十九・弍　整列ガイド
alignmnet guideはスタックで含まれる他のビューと整列する時使用されるカスタムプジションを定義する様に使用されます。これは center, firstText, lastText, leading, trailing などと標準整列ターフよりもっと複雑な整列を実装される様にします。例えば整列ガイドの長さは2/3の位置または上段で20point基準でビューを整列する時使用されることができます。
ビュー内の整列計算を助けるためにビューの幅と高さを得るのに使用されることができるViewDimensionsオブジェクトとビューの標準整列位置「.top, .bottom, .leading などと」がクロージャーに伝達されます。

![Screenshot 2023-12-11 at 4.34.10 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513806/06922909-5397-ac9c-53db-1b8d3cd5de7a.png)
alignmnet guideを使う時には alignmentGuide()`.修正者`に指定されたalignType親のスタックで適応されたものと一致するべきです。

offsetをハードコードングする代わりに、クロージャーで伝達されたViewDimensionsオブジェクトのプロパティをalignmentGuide位置を計算する事に利用できます。![Screenshot 2023-12-11 at 4.43.12 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513806/51391c01-f9bf-5fb4-f261-46bade416552.png)
ViewDimensionsオブジェクトはビューのHorizontalAlignmentとVerticalAlignmentプロパティに対する接近を提供します。![Screenshot 2023-12-11 at 4.48.37 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513806/5bfb0d83-4fe7-615b-f492-dead5c625f38.png)
# 二十九・参　整列ガイド道具使用する
alignmentGuideで慣れる一番いい方法は多様な設定でテストやってみる事です。幸いにもSwiftUI Labは多様な整列設定をテーストやってみる有用な学習道具を作りました。この道具を使用するためにAlginmentToolと言う名前の新しいSwiftUIプロジェクトを生成して、ContentView.swiftファイルをあげて既存のソースコードを全て削除します。次には、webで移動します。
残念だけどここのコードは今を基準で行わなかった。
bit.ly/2MCioyl
# 二十九・肆　カスタム整列ターフ
以前でした例題には標準整列ターフを基してビュー整列を変更してた。SwiftUIはカスタム整列ターフを宣言して標準ターフが拡張される様にします。例えば、oneThirdと言う名前のカスタム整列はターフはビューの指定された端から3/1距離位置で整列することが手木ます。

![Screenshot 2023-12-12 at 2.19.21 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513806/abc093cc-8eb6-de33-5952-eb82c001f15c.png)
ここで一つ以上の四角形だの整列をけを変えたい場合には適用された値を計算するための計算式をが含まれ**整列ガイド**を使う方法、他には**カスタム整列**を生成することです。これは計算された値を返却する新しい整列ターフを追加するためVerticalAlignmentとかHorizontalAlignmentを拡張してできます。次は新しい垂直整列ターフを生成する例です。
```diff_swift
extension VerticalAlignment {
    private enum OneThird: AlignmentID{
        static func defaultValue(in d: ViewDimensions)-> CGFloat {
            return d.height / 3
        }
    }
    static let oneThird = VerticalAlignment(OneThird.self)
}
```
> Extension ? In SwiftUI, extensions are a way to add new functionality or modify existing functionality to existing types (such as structs, enums, classes, protocols, etc.) without directly modifying their original implementation. Extensions provide a mechanism for extending the behavior of a type, making your code more modular and easier to read.

このextensionはAlignmentIDプロトコルを従うEnumを含めるべきで、defaultValue()と言う名前の関数が実装されるように指示します。この関数はビューに対するViewDimensionsオブジェクトをもらわなければならないし、整列ガイド位置を指す計算されたCGFloat値を
返却しなきゃならない。前の例題ではビュー高さの3/1が返却されます。
その様に実装されたら、カスタム整列はHStack宣言部で使用されることができます。
![Screenshot 2023-12-12 at 3.29.57 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513806/992d2c10-07db-2dd1-f95f-4e00527e725f.png)
二つの四角形全て付加的な修正なくでビューの上段を基準して計算されで整列されました。実は、カスタム整列は標準整列と同じ方法で使用者することができます。例えば、ビューの下の方を基準で赤い四角形を整列します。
![Screenshot 2023-12-12 at 4.32.24 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513806/4b3de295-172e-eef6-8cb8-dd0940e0a742.png)
二十九・伍　スタック整列交差する
標準整列ターフの主要な短所は他のスタくであるビューと整列する方法を提供しないことです。
![Screenshot 2023-12-12 at 4.46.03 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513806/9e4ae5ef-e6c0-bc2a-d1f4-afcda66e5e5b.png)
これを.top とか.bottom通じて緑四角形とかオレンジで整列することはできます。だが赤いものとか青いものと整列することは一般的にはできません。でも、カスタマ整列を丸とVStackである四角形で適用すればいいです。
```diff_swift
extension VerticalAlignment {
    private enum CrossAlignment: AlignmentID{
        static func defaultValue(in d: ViewDimensions)-> CGFloat {
            return d[.bottom]
        }
    }
    static let crossAlignment = VerticalAlignment(CrossAlignment.self)
}
```
その様に作ったカスタム整列は他のスタックで含まれているビューを整列するため使用できます。

# 二十九・淕
基本的にZStackの下位ビューは中央整列状態で上に重なるようになります。次の絵はZStackで三つの図形ビューが各格中央整列されたものを見せます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513806/4a0974a5-9e1d-2156-4fce-7dfe70d2b188.png)
標準整列ターフを使用すればスタックで属する全ての定列を変わることができます。次はZStackの整列を.leadingですることです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513806/e047119f-82bf-d189-ed41-de6782123ddf.png)
スタックである各ビューが自分だけの整列を持つ様にするレイアウトで適用すれば、水平と垂直のカスタム整列が一つの結合しなければならないです。
```diff_swift
extension HorizontalAlignment{
    enum MyHorizontal: AlignmentID{
        static func defaultValue(in d: ViewDimensions) -> CGFloat
        {d[HorizontalAlignment.center]}
    }
    static let myAlignment = HorizontalAlignment(MyHorizontal.self)
}
extension VerticalAlignment {
    enum MyVertical: AlignmentID{
        static func defaultValue(in d: ViewDimensions)-> CGFloat {
            return d[.bottom]
        }
    }
    static let crossAlignment = VerticalAlignment(MyVertical.self)
}
extension Alignment{
    static let myAlginment = Alignment(horizontal: .myAlignment,
                                       vertical: .myAlignment)
}
```
その様に実装するとカスタム整列はZStackの下位ビューを垂直・水平整列する様に使われることができます。
![Screenshot 2023-12-13 at 12.19.43 AM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513806/4533680e-271b-7710-cfab-d8efbbb26f6c.png)
ZStack カスタム整列がどう動作するかを理解するため各ビューの設定を変更してテストしてみよう。
![Screenshot 2023-12-13 at 12.27.28 AM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513806/4df161ad-e0fd-df23-705a-283482093e29.png)
# 二十九.柒 要約
SwiftUIスタックコンテナビューはコンテナを基準して全ての下位ビューの位置を調節する基本整列設定を利用して構成できます。スタックで属する個別ビューの整列はAlignmentGuideを使って使用することができます。これは、ViewDimensionオブジェクトが伝達されるclosureを含めます。このオブジェクトはビューの高さと幅を基してビューの位置を計算する様に使用されます。そのようなAlignmentGuideはスタックビューレイアウトを宣言する時で、StandardAlignmentと同一な方法で再利用することができるカスタム整列で実装されることもできます。customAlignmentは異なるスタックで含まれたビューがお互いにalignされるべきの場合に有用です。ZStackの下位ビューで対するcustomAlignmentは水平alignGuideと垂直alightGuide全てがひつよでした。