見出し画像

【じっくりSw1ftUI47】実践編17〜第29章 SwiftUIスタック配置と配置ガイド

さてと、前回

までのデータ周りの話とは打って変わって、今回からは、

ビューのデザイン

周りなんかを本格的にやってる部分に入ってく〜〜〜

これまでのサンプルコードなんかでも頻繁に、当たり前に、飽きるくらい使ってた

Stack View

周りを今回はやってく〜〜〜🕺

オイラの学び直しなんて不要って人は、

に丸々載ってるからそっちでやればいいんじゃね?👀
さてと、じゃ早速

じっくり第29章を読んでく👓

概要で、

スタックビューだけではなく、一歩先の

  • コンテナ

  • アラインメントガイド

  • カスタムアラインメントタイプ

  • 合わせ技

  • ZStack(多分、この章で実際のサンプルは初登場じゃないか?🧐)

も紹介してくぜ👍みたいなことを書いてんね👀(盛りだくさん😛)

まずは、コンテナから〜〜〜

どシンプルに

import SwiftUI

struct Essentials29ContentsView: View {
    var body: some View {
        Text("Hello,Swift")
    }
}

#Preview {
    Essentials29ContentsView()
}}

てなコードからスタートして〜〜〜〜

ホント、シンプル🤣

で、結構長丁場になりそうだし、色んなビューを大元のビューで管理しやすいように

import SwiftUI

struct Essentials29ContentsView: View {
    var body: some View {
        ScrollView{
            VStack{
                
            }
        }
    }
}

#Preview {
    Essentials29ContentsView()
}

てな感じで準備完了

import SwiftUI

struct Essentials29ContentsView: View {
    var body: some View {
        ScrollView{
            VStack{
                E29StandardVStackView()
            }
        }
    }
}

struct E29StandardVStackView:View {
    var body: some View {
        VStack{
            Text("🍎")
            Text("🦍")
            Text("🎺")
        }
    }
}
#Preview {
    Essentials29ContentsView()
}

てな感じで追記して

まずはこんな感じで縦に並んだ

正直醜いので〜〜〜

import SwiftUI

struct Essentials29ContentsView: View {
    var body: some View {
        ScrollView{
            VStack{
                E29StandardVStackView()
            }
        }
    }
}

struct E29StandardVStackView:View {
    var body: some View {
        VStack{
            Text("🍎")
                .font(.largeTitle)
            Text("🦍")
                .font(.largeTitle)
            Text("🎺")
                .font(.largeTitle)
        }
    }
}
#Preview {
    Essentials29ContentsView()
}
ちょいと大きく藁😆

でアラインメントを追加して〜〜〜

import SwiftUI

struct Essentials29ContentsView: View {
    var body: some View {
        ScrollView{
            VStack{
                E29StandardVStackView()
                E29TrailingVStackView()
            }
        }
    }
}
struct E29StandardVStackView:View {
    var body: some View {
        VStack{
            Text("🍎")
                .font(.largeTitle)
            Text("🦍")
                .font(.largeTitle)
            Text("🎺")
                .font(.largeTitle)
        }
    }
}
struct E29TrailingVStackView:View {
    var body: some View {
        VStack(alignment: .trailing){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍")
                .font(.largeTitle)
            Text("🎺")
                .font(.largeTitle)
        }
    }
}
#Preview {
    Essentials29ContentsView()
}

まずはてな感じにTrailingを追加してみたんだけど、

変化ないね👀💦

てのは実は当たり前で〜〜1文字しかないからね〜〜〜

import SwiftUI

struct Essentials29ContentsView: View {
    var body: some View {
        ScrollView{
            VStack{
                E29StandardVStackView()
                E29TrailingVStackView()
            }
        }
    }
}
struct E29StandardVStackView:View {
    var body: some View {
        VStack{
            Text("🍎")
                .font(.largeTitle)
            Text("🦍")
                .font(.largeTitle)
            Text("🎺")
                .font(.largeTitle)
        }
    }
}
struct E29TrailingVStackView:View {
    var body: some View {
        VStack(alignment: .trailing){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
            Text("🎺🎺🎺")
                .font(.largeTitle)
        }
    }
}
#Preview {
    Essentials29ContentsView()
}

てな感じでVStack内の文字を増やしてあげると〜〜〜

ハイ、右寄せになってるのを確認でけた〜〜〜

お次は、逆にleadingにしてみると〜〜〜

import SwiftUI

struct Essentials29ContentsView: View {
    var body: some View {
        ScrollView{
            VStack{
                E29StandardVStackView()
                E29TrailingVStackView()
                E29LeadingVStackView()
            }
        }
    }
}
struct E29StandardVStackView:View {
    var body: some View {
        VStack{
            Text("🍎")
                .font(.largeTitle)
            Text("🦍")
                .font(.largeTitle)
            Text("🎺")
                .font(.largeTitle)
        }
    }
}
struct E29TrailingVStackView:View {
    var body: some View {
        VStack(alignment: .trailing){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
            Text("🎺🎺🎺")
                .font(.largeTitle)
        }
    }
}
struct E29LeadingVStackView:View {
    var body: some View {
        VStack(alignment: .leading){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
            Text("🎺🎺🎺")
                .font(.largeTitle)
        }
    }
}
#Preview {
    Essentials29ContentsView()
}
てな感じで左寄せになった〜〜〜

HStackで遊ぶと〜〜〜

struct E29StandardHStackView:View {
    var body: some View {
        HStack{
            Text("🍎")
                .font(.largeTitle)
            Text("🦍")
                .font(.largeTitle)
            Text("🎺")
                .font(.largeTitle)
            Text("🐼")
                .font(.largeTitle)
        }
    }
}
まずは、基本でパンダを増やし〜〜〜

Topで遊ぶと

struct E29TopHStackView:View {
    var body: some View {
        HStack(alignment: .top){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
            Text("🎺🎺🎺")
                .font(.largeTitle)
            Text("🐼🐼🐼🐼")
                .font(.largeTitle)
        }
    }
}
てな感じ

bottomで遊ぶと

struct E29BottomHStackView:View {
    var body: some View {
        HStack(alignment: .bottom){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
            Text("🎺🎺🎺")
                .font(.largeTitle)
            Text("🐼🐼🐼🐼")
                .font(.largeTitle)
        }
    }
}
てな感じ

これで、

Alignment:配置

  • .leading:VStackで右揃え

  • .trailing:VStackで左揃え

  • .top:HStackで上揃え

  • .bottom:HStackで下揃え

てのが分かると思う🕺

スペースを使って〜〜〜

struct E29Spacing35VStackView:View {
    var body: some View {
        VStack(spacing: 35){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍")
                .font(.largeTitle)
            Text("🎺")
                .font(.largeTitle)
            Text("🐼")
                .font(.largeTitle)
        }
    }
}
struct E29Spacing35HStackView:View {
    var body: some View {
        HStack(spacing:35){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍")
                .font(.largeTitle)
            Text("🎺")
                .font(.largeTitle)
            Text("🐼")
                .font(.largeTitle)
        }
    }
}
てな感じで間の余白も調整できる〜〜〜

文字の大きさを変更しても、

struct E29multiFontSpacing35VStackView:View {
    var body: some View {
        VStack(alignment: .leading ,spacing: 35){
            Text("🍎🍎🍎🍎")
                .font(.largeTitle)
            Text("🦍🦍🦍")
                .font(.title)
            Text("🎺🎺")
                .font(.headline)
            Text("🐼")
                .font(.caption)
        }
    }
}
struct E29multiFontSpacing35HStackView:View {
    var body: some View {
        HStack(alignment: .bottom, spacing:35){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍")
                .font(.title)
            Text("🎺")
                .font(.headline)
            Text("🐼")
                .font(.caption)
        }
    }
}
てな感じで基準の線は揃った上でスペースも空けてくれる👀💦

さてと、お次は

アラインメントガイド

struct E29StandardAlignmentGuideView:View {
    var body: some View {
        VStack(alignment: .leading, spacing:35){
            Text("🍎🍎🍎🍎")
                .font(.largeTitle)
                .frame(width: 200,height: 150)
            Text("🦍🦍")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 300,height: 175)
            Text("🎺 🎺")
                .font(.largeTitle)
                .frame(width: 350,height: 200)
            Text("🐼 🐼 🐼")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 150,height: 150)
        }
    }
}

てな感じでFrameを追加してあげて、高さと幅を設定すると〜〜〜

てな感じでもできるし

幅だけ変えると〜〜〜

struct E29WidthOnlyChangeAlignmentGuideView:View {
    var body: some View {
        VStack(alignment: .leading, spacing:35){
            Text("🍎🍎🍎🍎")
                .font(.largeTitle)
                .frame(width: 200)
            Text("🦍🦍")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 300)
            Text("🎺 🎺")
                .font(.largeTitle)
                .frame(width: 350)
            Text("🐼 🐼 🐼")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 150)
        }
    }
}
VStackで左寄せなのに、開始位置が変わってることが分かるね

borderで線で囲んであげると

struct E29WidthOnlyChangeAlignmentGuideView:View {
    var body: some View {
        VStack(alignment: .leading, spacing:35){
            Text("🍎🍎🍎🍎")
                .font(.largeTitle)
                .frame(width: 200)
                .border(Color.black)
            Text("🦍🦍")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 300)
                .border(Color.black)
            Text("🎺 🎺")
                .font(.largeTitle)
                .frame(width: 350)
                .border(Color.black)
            Text("🐼 🐼 🐼")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 150)
                .border(Color.black)
        }
    }
}
てな感じで、何でこんな配置になっているか一目瞭然🕺

ここでAlignmentGuideを🎺に追加してみると〜〜〜

struct E29AddedAlignmentGuideView:View {
    var body: some View {
        VStack(alignment: .leading, spacing:35){
            Text("🍎🍎🍎🍎")
                .font(.largeTitle)
                .frame(width: 200)
                .border(Color.black)
            Text("🦍🦍")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 300)
                .border(Color.black)
            Text("🎺 🎺")
                .font(.largeTitle)
                .alignmentGuide(.leading, computeValue: { dimension in
                    120.0
                })
                .frame(width: 350)
                .border(Color.black)
            Text("🐼 🐼 🐼")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 150)
                .border(Color.black)
        }
    }
}
てな感じで、開始位置が全く変わって、
他の3つの🍎、🦍、🐼の表示位置も変わったことが分かるね👀

ハードコーディングでの調整ではなく

struct E29AdjustedAlignmentGuideView:View {
    var body: some View {
        VStack(alignment: .leading, spacing:35){
            Text("🍎🍎🍎🍎")
                .font(.largeTitle)
                .frame(width: 200)
                .border(Color.black)
            Text("🦍🦍")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 300)
                .border(Color.black)
            Text("🎺 🎺")
                .font(.largeTitle)
                .alignmentGuide(.leading, computeValue: { dimension in
                    dimension.width / 7
                })
                .frame(width: 350)
                .border(Color.black)
            Text("🐼 🐼 🐼")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 150)
                .border(Color.black)
        }
    }
}

てな感じで、

相対的に位置を計算させることも可能👀💦

ただ計算とか相対位置を出してるだけだから、VStackとかHStackの配置設定に直接設定もできるみたいだね👀

struct E29AccessedAlignmentValueVStackView:View {
    var body: some View {
        VStack(alignment: .trailing){
            Text("🍎")
                .alignmentGuide(.trailing, computeValue: { dimension in
                    dimension[HorizontalAlignment.leading] + 300
                })
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
            Text("🎺🎺🎺")
                .alignmentGuide(.trailing, computeValue: { dimension in
                    dimension[HorizontalAlignment.trailing] - 30
                })
                .font(.largeTitle)
            Text("🐼🐼🐼🐼")
                .font(.largeTitle)
        }
    }
}

てな感じにすると

てな感じで、ビュー単位で細かい調整も可能

カスタムアラインメントタイプ

ここまで来ると、

VStackとかHStackなんかのビュー自体もカスタマイズできるね👀

ってのが分かると思うので〜〜〜

struct E29CustomHStackView:View {
    var body: some View {
        HStack{
            Text("🍎")
                .font(.largeTitle)
            Text("🦍")
                .font(.largeTitle)
            Text("🎺")
                .font(.largeTitle)
            Text("🐼")
                .font(.largeTitle)
        }
    }
}

まずはシンプルなHStackを用意して〜〜〜シンタックス編でやった

拡張:extension

で〜〜〜

extension VerticalAlignment{
    private enum Pentagon: AlignmentID {
        static func defaultValue(in dimension: ViewDimensions) -> CGFloat {
            return dimension.height / 5
        }
    }
    private enum Quarter: AlignmentID {
        static func defaultValue(in dimension: ViewDimensions) -> CGFloat {
            return dimension.height / 4
        }
    }
    static let penta = VerticalAlignment(Pentagon.self)
    static let quarter = VerticalAlignment(Quarter.self)
}

てな感じの5分の1と4分の1にするものを用意して

struct E29CustomedPentaHStackView:View {
    var body: some View {
        HStack(alignment: .penta){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
                .alignmentGuide(.penta, computeValue: { dimension in
                    dimension[VerticalAlignment.top]
                })
            Text("🎺🎺")
                .font(.largeTitle)
            Text("🐼")
                .font(.largeTitle)
                .alignmentGuide(.penta, computeValue: { dimension in
                    dimension[VerticalAlignment.top]
                })
        }
    }
}
struct E29CustomedQuarterHStackView:View {
    var body: some View {
        HStack(alignment: .quarter){
            Text("🍎🍎")
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
                .alignmentGuide(.quarter, computeValue: { dimension in
                    dimension[VerticalAlignment.top]
                })
            Text("🎺🎺")
                .font(.largeTitle)
            Text("🐼🐼")
                .font(.largeTitle)
                .alignmentGuide(.quarter, computeValue: { dimension in
                    dimension[VerticalAlignment.top]
                })
        }
    }
}

てな感じのコードを書いて動かすと〜〜〜

高さの微調整ができてることが分かるね👀💦
コイツはかっちょいいビューを作りたい時に使える🕺
struct E29CustomedPentaHStackView:View {
    var body: some View {
        HStack(alignment: .penta){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
                .alignmentGuide(.penta, computeValue: { dimension in
                    dimension[VerticalAlignment.bottom]
                })
            Text("🎺🎺")
                .font(.largeTitle)
            Text("🐼")
                .font(.largeTitle)
                .alignmentGuide(.penta, computeValue: { dimension in
                    dimension[VerticalAlignment.top]
                })
        }
    }
}
struct E29CustomedQuarterHStackView:View {
    var body: some View {
        HStack(alignment: .quarter){
            Text("🍎🍎")
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
                .alignmentGuide(.quarter, computeValue: { dimension in
                    dimension[VerticalAlignment.top]
                })
            Text("🎺🎺")
                .font(.largeTitle)
            Text("🐼🐼")
                .font(.largeTitle)
                .alignmentGuide(.quarter, computeValue: { dimension in
                    dimension[VerticalAlignment.bottom]
                })
        }
    }
}

てtop→bottomに一部を変更してあげるだけで〜

こんな感じにもなるし〜〜〜

以前の記事でも書いたけど、拡張は元々あるビューとかプロトコルの設定を丸ごと変えてしまうくらい強力な場合も出てくるので、この章で作ったと分かるように

みたいな感じでSwiftFileで
てな感じでな名前でファイルを作って〜〜〜

名前もそれぞれ

import Foundation
import SwiftUI

extension VerticalAlignment{
    private enum E29Pentagon: AlignmentID {
        static func defaultValue(in dimension: ViewDimensions) -> CGFloat {
            return dimension.height / 5
        }
    }
    private enum E29Quarter: AlignmentID {
        static func defaultValue(in dimension: ViewDimensions) -> CGFloat {
            return dimension.height / 4
        }
    }
    static let e29Penta = VerticalAlignment(E29Pentagon.self)
    static let e29Quarter = VerticalAlignment(E29Quarter.self)
}

てな感じで変更して、管理しやすいようにしとこう🕺
それに合わせて、さっきまでのコードも

struct E29CustomedPentaHStackView:View {
    var body: some View {
        HStack(alignment: .e29Penta){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
                .alignmentGuide(.e29Penta, computeValue: { dimension in
                    dimension[VerticalAlignment.bottom]
                })
            Text("🎺🎺")
                .font(.largeTitle)
            Text("🐼")
                .font(.largeTitle)
                .alignmentGuide(.e29Penta, computeValue: { dimension in
                    dimension[VerticalAlignment.top]
                })
        }
    }
}
struct E29CustomedQuarterHStackView:View {
    var body: some View {
        HStack(alignment: .e29Quarter){
            Text("🍎🍎")
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
                .alignmentGuide(.e29Quarter, computeValue: { dimension in
                    dimension[VerticalAlignment.top]
                })
            Text("🎺🎺")
                .font(.largeTitle)
            Text("🐼🐼")
                .font(.largeTitle)
                .alignmentGuide(.e29Quarter, computeValue: { dimension in
                    dimension[VerticalAlignment.bottom]
                })
        }
    }
}

てな感じにしとく🕺お次は、

合わせ技

VStackとHStackの組み合わせを紹介🕺
まずは、

struct E29CrossedStackView:View {
    var body: some View {
        HStack(alignment: .center,spacing: 35){
            Text("しりとり")

            VStack{
                Text("🍎")
                    .font(.largeTitle)
                Text("🦍")
                    .font(.largeTitle)
                Text("🎺")
                    .font(.largeTitle)
                Text("🐼")
                    .font(.largeTitle)
                Text("💃")
                    .font(.largeTitle)
                Text("🍉")
                    .font(.largeTitle)
                Text("🦛")
                    .font(.largeTitle)
            }
        }
    }
}

てな感じで単純に組み合わせると、、、

すでにかなり面白いことになってるんだけど、
import Foundation
import SwiftUI

extension VerticalAlignment{
    private enum E29Pentagon: AlignmentID {
        static func defaultValue(in dimension: ViewDimensions) -> CGFloat {
            return dimension.height / 5
        }
    }
    private enum E29Quarter: AlignmentID {
        static func defaultValue(in dimension: ViewDimensions) -> CGFloat {
            return dimension.height / 4
        }
    }
    private enum E29CrossAlignment: AlignmentID {
        static func defaultValue(in dimension: ViewDimensions) -> CGFloat {
            return dimension[.top]
        }
    }
    static let e29Penta = VerticalAlignment(E29Pentagon.self)
    static let e29Quarter = VerticalAlignment(E29Quarter.self)
    static let e29Cross = VerticalAlignment(E29CrossAlignment.self)
}

てな感じでさっきの拡張に追記してあげて〜〜〜

struct E29CrossedStackView:View {
    var body: some View {
        HStack(alignment: .e29Cross,spacing: 35){
            Text("しりとり")
                .font(.largeTitle)

            VStack{
                Text("🍎:りんご")
                    .font(.largeTitle)
                Text("🦍:ゴリラ")
                    .font(.largeTitle)
                    .alignmentGuide(.e29Cross, computeValue: { dimension in
                        dimension[VerticalAlignment.center]
                    })
                Text("🎺:ラッパ")
                    .font(.largeTitle)
                Text("🐼:パンダ")
                    .font(.largeTitle)
                Text("💃:ダンス")
                    .font(.largeTitle)
                Text("🍉:スイカ")
                    .font(.largeTitle)
                    .alignmentGuide(.e29Cross, computeValue: { dimension in
                        dimension[VerticalAlignment.center]
                    })
                Text("🦛:カバ")
                    .font(.largeTitle)
            }
        }
    }
}

てな感じで遊ぶと、、、

みたいな感じで調整もできるね👀

ZStackカスタム

と、29章目にしていきなり、ZStackがカスタムから出てきてんだけど、馴染みのない人にはわからないと思うので、

まずはZStackってなに

struct E29StandardZStackView: View {
    var body: some View {
        ZStack{
            Rectangle()
                .foregroundStyle(Color.green)
                .frame(width: 300, height: 300)
            Circle()
                .foregroundStyle(Color.orange)
                .frame(width: 200, height: 200)
            Capsule()
                .foregroundStyle(Color.red)
                .frame(width: 150, height: 100)
        }
    }
}

みたいなコードを書いてプレビューをみると分かるんだけど

てな感じで

要は、

ZStack:レイヤーみたいなイメージで、ビューを重ねる感じ
👉一番最初のビューが一番下で、どんどん手前に来る感じ

なので

struct E29StandardZStackView: View {
    var body: some View {
        ZStack{
            Rectangle()
                .foregroundStyle(Color.green)
                .frame(width: 300, height: 300)
            Circle()
                .foregroundStyle(Color.orange)
                .frame(width: 200, height: 200)
            Capsule()
                .foregroundStyle(Color.red)
                .frame(width: 450, height: 400)
        }
    }
}

なんかで一番手前に来る最後のビューを最大にしちゃうと

もちろん、下のレイヤーは見えなくなっちゃう

ま、PhotoShopとかやってれば当たり前に分かると思うけどね〜〜〜

ここでポイント①:Stackビューまとめ

  • VStack:ビューを縦に並べる

  • HStack:ビューを横に並べる

  • ZStack:ビューを重ねる

こんだけ藁😆
さてと元に戻して本題へ〜〜〜

じゃ、ZStackを実際にカスタマイズしていこう

さっき作った拡張に下記な感じで追記〜〜〜

import Foundation
import SwiftUI

extension VerticalAlignment{
    private enum E29Pentagon: AlignmentID {
        static func defaultValue(in dimension: ViewDimensions) -> CGFloat {
            return dimension.height / 5
        }
    }
    private enum E29Quarter: AlignmentID {
        static func defaultValue(in dimension: ViewDimensions) -> CGFloat {
            return dimension.height / 4
        }
    }
    private enum E29CrossAlignment: AlignmentID {
        static func defaultValue(in dimension: ViewDimensions) -> CGFloat {
            return dimension[.top]
        }
    }
    private enum E29Custom: AlignmentID{
        static func defaultValue(in dimension: ViewDimensions) -> CGFloat {
            return dimension[VerticalAlignment.center]
        }
    }
    static let e29Penta = VerticalAlignment(E29Pentagon.self)
    static let e29Quarter = VerticalAlignment(E29Quarter.self)
    static let e29Cross = VerticalAlignment(E29CrossAlignment.self)
    static let e29Custom = VerticalAlignment(E29Custom.self)
}

extension HorizontalAlignment {
    enum E29Horizontal: AlignmentID{
        static func defaultValue(in dimension: ViewDimensions) -> CGFloat {
            dimension[HorizontalAlignment.center]
        }
    }
    static let e29Horizontal = HorizontalAlignment(E29Horizontal.self)
}

extension Alignment {
    static let e29Alignment = Alignment(horizontal: .e29Horizontal, vertical: .e29Custom)
}

んでもってさっき作ったZStackに組み込み〜〜〜

struct E29CustomedZStackView: View {
    var body: some View {
        ZStack(alignment: .e29Alignment){
            Rectangle()
                .foregroundStyle(Color.green)
                .alignmentGuide(HorizontalAlignment.e29Horizontal, computeValue: { dimension in
                    dimension[.trailing]
                })
                .alignmentGuide(VerticalAlignment.e29Custom, computeValue: { dimension in
                    dimension[VerticalAlignment.bottom]
                })
                .frame(width: 300, height: 300)
            Circle()
                .foregroundStyle(Color.orange)
                .alignmentGuide(VerticalAlignment.e29Custom, computeValue: { dimension in
                    dimension[VerticalAlignment.top]
                })
                .alignmentGuide(HorizontalAlignment.e29Horizontal, computeValue: { dimension in
                    dimension[HorizontalAlignment.center]
                })
                .frame(width: 200, height: 200)
            Capsule()
                .foregroundStyle(Color.red)
                .alignmentGuide(HorizontalAlignment.e29Horizontal, computeValue: { dimension in
                    dimension[.leading]
                })
                .alignmentGuide(VerticalAlignment.e29Custom, computeValue: { dimension in
                    dimension[.bottom]
                })
                .frame(width: 150, height: 100)
        }
    }
}

てな感じにすると

てな感じにもできるし
struct E29EachCustomedZStackView: View {
    var body: some View {
        ZStack(alignment: .e29Alignment){
            Rectangle()
                .foregroundStyle(Color.green)
                .alignmentGuide(HorizontalAlignment.e29Horizontal, computeValue: { dimension in
                    dimension[.leading]
                })
                .alignmentGuide(VerticalAlignment.e29Custom, computeValue: { dimension in
                    dimension[VerticalAlignment.bottom]
                })
                .frame(width: 300, height: 300)
            Circle()
                .foregroundStyle(Color.orange)
                .alignmentGuide(VerticalAlignment.e29Custom, computeValue: { dimension in
                    dimension[VerticalAlignment.center]
                })
                .alignmentGuide(HorizontalAlignment.e29Horizontal, computeValue: { dimension in
                    dimension[HorizontalAlignment.trailing]
                })
                .frame(width: 200, height: 200)
            Capsule()
                .foregroundStyle(Color.red)
                .alignmentGuide(HorizontalAlignment.e29Horizontal, computeValue: { dimension in
                    dimension[.leading]
                })
                .alignmentGuide(VerticalAlignment.e29Custom, computeValue: { dimension in
                    dimension[.top]
                })
                .frame(width: 150, height: 100)
        }
    }
}

てな感じで変更すると、、、

てな感じで相対的に各ビューとの位置関係から配置もできる🕺

ここでポイント②:配置は正直、

頭で理解して計算とかするよりも、

自分で動かしながらで色々試してみるしかないし、そっちの方が早い

あまり、頭ばっかりでやってると、

  • モディファイアの優先順位を見誤る

  • ビューの配置で計算通りにいかないと余計な時間を消費する

からね〜〜〜

最近のオープンソースでオブジェクト指向言語は顕著だけど、

  • 論より証拠

  • 案ずるより産むが易し

で動かした方が早い

机上デバッグとか論理的にとか、建築で例えるとみたいな人もいるけど、
机上はあくまでお机上だし、動きも具体的にイメージできない人が動かす前から論理的になんて言っても、全ての機能の動きも理論的に網羅もしてない段階で何を論理的に考えるのか不思議だし、実際に有体物を使って犬小屋とか家を作るわけでもなく、バックアップも取れて失敗したら元に戻せるし、プレビューですぐに実行結果がわかるのに、

わざわざ机上で考えるだけ時間の無駄

てかXcodeがそのために、プレビューとかシミュレータを用意してくれてる機能を使わずに頭ばっかりで考えるとか

Swiftの旨みを完全に殺してるようなもの

だからこのマガジンの冒頭でゆーたとおり、

何で学ぶのかを考えた方がいいってゆーてるだけ

断言してもいいことなんだけど、

何かのサンプルコードとか機能を知るたびに、

  • 1を聞いて10を知ろうとする

  • じっくり考えて、ちゃんと理解して、それから自分で空を組めるようになって

  • ゼロから自分で生み出して初めてコードを実行する

みたいなレガシー言語時代のフェーズ型(ウォーターフォール)みたいな職人像を無責任に抱いてやってる人も多いけど、

コードなんて動かさないで理解できるわけないし、
自分でゼロから書くとかやるよりも
多くのサンプルコードにスパスパ触れて
サクサク組み込んでコードをテスト系で動かして早めに沢山失敗してる人の方が

明らかに吸収も理解も上達も早いよ〜〜〜〜
てか、実際の現場では後者の人しか生き残ってないし、続いてない
👉木を見て森を見ずでも、森見て木を見ずもダメ
💃早めに沢山のサンプルコードを実際に動かして1周回るが一番の近道🕺

今回のまとめコード

import SwiftUI

struct Essentials29ContentsView: View {
    var body: some View {
        ScrollView{
            VStack{
                E29StandardVStackView()
                E29TrailingVStackView()
                E29LeadingVStackView()
                E29StandardHStackView()
                E29TopHStackView()
                E29BottomHStackView()
                E29Spacing35VStackView()
                E29Spacing35HStackView()
                E29multiFontSpacing35VStackView()
                E29multiFontSpacing35HStackView()
                E29StandardAlignmentGuideView()
                E29WidthOnlyChangeAlignmentGuideView()
                E29AddedAlignmentGuideView()
                E29AdjustedAlignmentGuideView()
                E29AccessedAlignmentValueVStackView()
                E29CustomHStackView()
                E29CustomedPentaHStackView()
                E29CustomedQuarterHStackView()
                E29CrossedStackView()
                E29StandardZStackView()
                E29CustomedZStackView()
                E29EachCustomedZStackView()
            }
        }
    }
}
struct E29StandardVStackView:View {
    var body: some View {
        VStack{
            Text("🍎")
                .font(.largeTitle)
            Text("🦍")
                .font(.largeTitle)
            Text("🎺")
                .font(.largeTitle)
        }
    }
}
struct E29TrailingVStackView:View {
    var body: some View {
        VStack(alignment: .trailing){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
            Text("🎺🎺🎺")
                .font(.largeTitle)
        }
    }
}
struct E29LeadingVStackView:View {
    var body: some View {
        VStack(alignment: .leading){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
            Text("🎺🎺🎺")
                .font(.largeTitle)
        }
    }
}
struct E29StandardHStackView:View {
    var body: some View {
        HStack{
            Text("🍎")
                .font(.largeTitle)
            Text("🦍")
                .font(.largeTitle)
            Text("🎺")
                .font(.largeTitle)
            Text("🐼")
                .font(.largeTitle)
        }
    }
}
struct E29TopHStackView:View {
    var body: some View {
        HStack(alignment: .top){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
            Text("🎺🎺🎺")
                .font(.largeTitle)
            Text("🐼🐼🐼🐼")
                .font(.largeTitle)
        }
    }
}
struct E29BottomHStackView:View {
    var body: some View {
        HStack(alignment: .bottom){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
            Text("🎺🎺🎺")
                .font(.largeTitle)
            Text("🐼🐼🐼🐼")
                .font(.largeTitle)
        }
    }
}
struct E29Spacing35VStackView:View {
    var body: some View {
        VStack(spacing: 35){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍")
                .font(.largeTitle)
            Text("🎺")
                .font(.largeTitle)
            Text("🐼")
                .font(.largeTitle)
        }
    }
}
struct E29Spacing35HStackView:View {
    var body: some View {
        HStack(spacing:35){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍")
                .font(.largeTitle)
            Text("🎺")
                .font(.largeTitle)
            Text("🐼")
                .font(.largeTitle)
        }
    }
}

struct E29multiFontSpacing35VStackView:View {
    var body: some View {
        VStack(alignment: .leading ,spacing: 35){
            Text("🍎🍎🍎🍎")
                .font(.largeTitle)
            Text("🦍🦍🦍")
                .font(.title)
            Text("🎺🎺")
                .font(.headline)
            Text("🐼")
                .font(.caption)
        }
    }
}
struct E29multiFontSpacing35HStackView:View {
    var body: some View {
        HStack(alignment: .bottom, spacing:35){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍")
                .font(.title)
            Text("🎺")
                .font(.headline)
            Text("🐼")
                .font(.caption)
        }
    }
}
struct E29StandardAlignmentGuideView:View {
    var body: some View {
        VStack(alignment: .leading, spacing:35){
            Text("🍎🍎🍎🍎")
                .font(.largeTitle)
                .frame(width: 200,height: 150)
            Text("🦍🦍")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 300,height: 175)
            Text("🎺 🎺")
                .font(.largeTitle)
                .frame(width: 350,height: 200)
            Text("🐼 🐼 🐼")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 150,height: 150)
        }
    }
}
struct E29WidthOnlyChangeAlignmentGuideView:View {
    var body: some View {
        VStack(alignment: .leading, spacing:35){
            Text("🍎🍎🍎🍎")
                .font(.largeTitle)
                .frame(width: 200)
                .border(Color.black)
            Text("🦍🦍")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 300)
                .border(Color.black)
            Text("🎺 🎺")
                .font(.largeTitle)
                .frame(width: 350)
                .border(Color.black)
            Text("🐼 🐼 🐼")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 150)
                .border(Color.black)
        }
    }
}
struct E29AddedAlignmentGuideView:View {
    var body: some View {
        VStack(alignment: .leading, spacing:35){
            Text("🍎🍎🍎🍎")
                .font(.largeTitle)
                .frame(width: 200)
                .border(Color.black)
            Text("🦍🦍")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 300)
                .border(Color.black)
            Text("🎺 🎺")
                .font(.largeTitle)
                .alignmentGuide(.leading, computeValue: { dimension in
                    120.0
                })
                .frame(width: 350)
                .border(Color.black)
            Text("🐼 🐼 🐼")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 150)
                .border(Color.black)
        }
    }
}
struct E29AdjustedAlignmentGuideView:View {
    var body: some View {
        VStack(alignment: .leading, spacing:35){
            Text("🍎🍎🍎🍎")
                .font(.largeTitle)
                .frame(width: 200)
                .border(Color.black)
            Text("🦍🦍")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 300)
                .border(Color.black)
            Text("🎺 🎺")
                .font(.largeTitle)
                .alignmentGuide(.leading, computeValue: { dimension in
                    dimension.width / 7
                })
                .frame(width: 350)
                .border(Color.black)
            Text("🐼 🐼 🐼")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 150)
                .border(Color.black)
        }
    }
}
struct E29AccessedAlignmentValueVStackView:View {
    var body: some View {
        VStack(alignment: .trailing){
            Text("🍎")
                .alignmentGuide(.trailing, computeValue: { dimension in
                    dimension[HorizontalAlignment.leading] + 300
                })
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
            Text("🎺🎺🎺")
                .alignmentGuide(.trailing, computeValue: { dimension in
                    dimension[HorizontalAlignment.trailing] - 30
                })
                .font(.largeTitle)
            Text("🐼🐼🐼🐼")
                .font(.largeTitle)
        }
    }
}
struct E29CustomHStackView:View {
    var body: some View {
        HStack{
            Text("🍎")
                .font(.largeTitle)
            Text("🦍")
                .font(.largeTitle)
            Text("🎺")
                .font(.largeTitle)
            Text("🐼")
                .font(.largeTitle)
        }
    }
}

struct E29CustomedPentaHStackView:View {
    var body: some View {
        HStack(alignment: .e29Penta){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
                .alignmentGuide(.e29Penta, computeValue: { dimension in
                    dimension[VerticalAlignment.bottom]
                })
            Text("🎺🎺")
                .font(.largeTitle)
            Text("🐼")
                .font(.largeTitle)
                .alignmentGuide(.e29Penta, computeValue: { dimension in
                    dimension[VerticalAlignment.top]
                })
        }
    }
}
struct E29CustomedQuarterHStackView:View {
    var body: some View {
        HStack(alignment: .e29Quarter){
            Text("🍎🍎")
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
                .alignmentGuide(.e29Quarter, computeValue: { dimension in
                    dimension[VerticalAlignment.top]
                })
            Text("🎺🎺")
                .font(.largeTitle)
            Text("🐼🐼")
                .font(.largeTitle)
                .alignmentGuide(.e29Quarter, computeValue: { dimension in
                    dimension[VerticalAlignment.bottom]
                })
        }
    }
}
struct E29CrossedStackView:View {
    var body: some View {
        HStack(alignment: .e29Cross,spacing: 35){
            Text("しりとり")
                .font(.largeTitle)

            VStack{
                Text("🍎:りんご")
                    .font(.largeTitle)
                Text("🦍:ゴリラ")
                    .font(.largeTitle)
                    .alignmentGuide(.e29Cross, computeValue: { dimension in
                        dimension[VerticalAlignment.center]
                    })
                Text("🎺:ラッパ")
                    .font(.largeTitle)
                Text("🐼:パンダ")
                    .font(.largeTitle)
                Text("💃:ダンス")
                    .font(.largeTitle)
                Text("🍉:スイカ")
                    .font(.largeTitle)
                    .alignmentGuide(.e29Cross, computeValue: { dimension in
                        dimension[VerticalAlignment.center]
                    })
                Text("🦛:カバ")
                    .font(.largeTitle)
            }
        }
    }
}
struct E29StandardZStackView: View {
    var body: some View {
        ZStack(alignment: .e29Alignment){
            Rectangle()
                .foregroundStyle(Color.green)
                .frame(width: 300, height: 300)
            Circle()
                .foregroundStyle(Color.orange)
                .frame(width: 200, height: 200)
            Capsule()
                .foregroundStyle(Color.red)
                .frame(width: 150, height: 100)
        }
    }
}
struct E29CustomedZStackView: View {
    var body: some View {
        ZStack(alignment: .e29Alignment){
            Rectangle()
                .foregroundStyle(Color.green)
                .alignmentGuide(HorizontalAlignment.e29Horizontal, computeValue: { dimension in
                    dimension[.trailing]
                })
                .alignmentGuide(VerticalAlignment.e29Custom, computeValue: { dimension in
                    dimension[VerticalAlignment.bottom]
                })
                .frame(width: 300, height: 300)
            Circle()
                .foregroundStyle(Color.orange)
                .alignmentGuide(VerticalAlignment.e29Custom, computeValue: { dimension in
                    dimension[VerticalAlignment.top]
                })
                .alignmentGuide(HorizontalAlignment.e29Horizontal, computeValue: { dimension in
                    dimension[HorizontalAlignment.center]
                })
                .frame(width: 200, height: 200)
            Capsule()
                .foregroundStyle(Color.red)
                .alignmentGuide(HorizontalAlignment.e29Horizontal, computeValue: { dimension in
                    dimension[.leading]
                })
                .alignmentGuide(VerticalAlignment.e29Custom, computeValue: { dimension in
                    dimension[.bottom]
                })
                .frame(width: 150, height: 100)
        }
    }
}
struct E29EachCustomedZStackView: View {
    var body: some View {
        ZStack(alignment: .e29Alignment){
            Rectangle()
                .foregroundStyle(Color.green)
                .alignmentGuide(HorizontalAlignment.e29Horizontal, computeValue: { dimension in
                    dimension[.leading]
                })
                .alignmentGuide(VerticalAlignment.e29Custom, computeValue: { dimension in
                    dimension[VerticalAlignment.bottom]
                })
                .frame(width: 300, height: 300)
            Circle()
                .foregroundStyle(Color.orange)
                .alignmentGuide(VerticalAlignment.e29Custom, computeValue: { dimension in
                    dimension[VerticalAlignment.center]
                })
                .alignmentGuide(HorizontalAlignment.e29Horizontal, computeValue: { dimension in
                    dimension[HorizontalAlignment.trailing]
                })
                .frame(width: 200, height: 200)
            Capsule()
                .foregroundStyle(Color.red)
                .alignmentGuide(HorizontalAlignment.e29Horizontal, computeValue: { dimension in
                    dimension[.leading]
                })
                .alignmentGuide(VerticalAlignment.e29Custom, computeValue: { dimension in
                    dimension[.top]
                })
                .frame(width: 150, height: 100)
        }
    }
}
#Preview {
    Essentials29ContentsView()
}
import Foundation
import SwiftUI

extension VerticalAlignment{
    private enum E29Pentagon: AlignmentID {
        static func defaultValue(in dimension: ViewDimensions) -> CGFloat {
            return dimension.height / 5
        }
    }
    private enum E29Quarter: AlignmentID {
        static func defaultValue(in dimension: ViewDimensions) -> CGFloat {
            return dimension.height / 4
        }
    }
    private enum E29CrossAlignment: AlignmentID {
        static func defaultValue(in dimension: ViewDimensions) -> CGFloat {
            return dimension[.top]
        }
    }
    private enum E29Custom: AlignmentID{
        static func defaultValue(in dimension: ViewDimensions) -> CGFloat {
            return dimension[VerticalAlignment.center]
        }
    }
    static let e29Penta = VerticalAlignment(E29Pentagon.self)
    static let e29Quarter = VerticalAlignment(E29Quarter.self)
    static let e29Cross = VerticalAlignment(E29CrossAlignment.self)
    static let e29Custom = VerticalAlignment(E29Custom.self)
}

extension HorizontalAlignment {
    enum E29Horizontal: AlignmentID{
        static func defaultValue(in dimension: ViewDimensions) -> CGFloat {
            dimension[HorizontalAlignment.center]
        }
    }
    static let e29Horizontal = HorizontalAlignment(E29Horizontal.self)
}

extension Alignment {
    static let e29Alignment = Alignment(horizontal: .e29Horizontal, vertical: .e29Custom)
}

Apple公式

さてと、次回は

ビューの配置で、単純にビューばかりを繋いでいくと今回みたいに

ごちゃごちゃする

ってことがわかったところで、項目を綺麗にスッキリまとめる機能のひとつ

第30章 SwiftUI リストとナビゲーション

についてやってく〜〜〜

記事公開後、

いつもどおり、

でやった操作を〜〜〜

てな
てな
てなの
てな感じ

サンプルコード

◾️Essentials29.swift

import SwiftUI
import WebKit

//タイトル
let essentialsChapter29NavigationTitle = "第29章"
let essentialsChapter29Title = "第29章 SwiftUIスタック配置と配置ガイド"
let essentialsChapter29SubTitle = "第1節 SwiftUIスタック配置と配置ガイド"

//コード
let codeEssentials29 = """
import Foundation
import SwiftUI

extension VerticalAlignment{
    private enum E29Pentagon: AlignmentID {
        static func defaultValue(in dimension: ViewDimensions) -> CGFloat {
            return dimension.height / 5
        }
    }
    private enum E29Quarter: AlignmentID {
        static func defaultValue(in dimension: ViewDimensions) -> CGFloat {
            return dimension.height / 4
        }
    }
    private enum E29CrossAlignment: AlignmentID {
        static func defaultValue(in dimension: ViewDimensions) -> CGFloat {
            return dimension[.top]
        }
    }
    private enum E29Custom: AlignmentID{
        static func defaultValue(in dimension: ViewDimensions) -> CGFloat {
            return dimension[VerticalAlignment.center]
        }
    }
    static let e29Penta = VerticalAlignment(E29Pentagon.self)
    static let e29Quarter = VerticalAlignment(E29Quarter.self)
    static let e29Cross = VerticalAlignment(E29CrossAlignment.self)
    static let e29Custom = VerticalAlignment(E29Custom.self)
}

extension HorizontalAlignment {
    enum E29Horizontal: AlignmentID{
        static func defaultValue(in dimension: ViewDimensions) -> CGFloat {
            dimension[HorizontalAlignment.center]
        }
    }
    static let e29Horizontal = HorizontalAlignment(E29Horizontal.self)
}

extension Alignment {
    static let e29Alignment = Alignment(horizontal: .e29Horizontal, vertical: .e29Custom)
}

struct Essentials29ContentsView: View {
    var body: some View {
        ScrollView{
            VStack{
                E29StandardVStackView()
                E29TrailingVStackView()
                E29LeadingVStackView()
                E29StandardHStackView()
                E29TopHStackView()
                E29BottomHStackView()
                E29Spacing35VStackView()
                E29Spacing35HStackView()
                E29multiFontSpacing35VStackView()
                E29multiFontSpacing35HStackView()
                E29StandardAlignmentGuideView()
                E29WidthOnlyChangeAlignmentGuideView()
                E29AddedAlignmentGuideView()
                E29AdjustedAlignmentGuideView()
                E29AccessedAlignmentValueVStackView()
                E29CustomHStackView()
                E29CustomedPentaHStackView()
                E29CustomedQuarterHStackView()
                E29CrossedStackView()
                E29StandardZStackView()
                E29CustomedZStackView()
                E29EachCustomedZStackView()
            }
        }
    }
}
struct E29StandardVStackView:View {
    var body: some View {
        VStack{
            Text("🍎")
                .font(.largeTitle)
            Text("🦍")
                .font(.largeTitle)
            Text("🎺")
                .font(.largeTitle)
        }
    }
}
struct E29TrailingVStackView:View {
    var body: some View {
        VStack(alignment: .trailing){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
            Text("🎺🎺🎺")
                .font(.largeTitle)
        }
    }
}
struct E29LeadingVStackView:View {
    var body: some View {
        VStack(alignment: .leading){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
            Text("🎺🎺🎺")
                .font(.largeTitle)
        }
    }
}
struct E29StandardHStackView:View {
    var body: some View {
        HStack{
            Text("🍎")
                .font(.largeTitle)
            Text("🦍")
                .font(.largeTitle)
            Text("🎺")
                .font(.largeTitle)
            Text("🐼")
                .font(.largeTitle)
        }
    }
}
struct E29TopHStackView:View {
    var body: some View {
        HStack(alignment: .top){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
            Text("🎺🎺🎺")
                .font(.largeTitle)
            Text("🐼🐼🐼🐼")
                .font(.largeTitle)
        }
    }
}
struct E29BottomHStackView:View {
    var body: some View {
        HStack(alignment: .bottom){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
            Text("🎺🎺🎺")
                .font(.largeTitle)
            Text("🐼🐼🐼🐼")
                .font(.largeTitle)
        }
    }
}
struct E29Spacing35VStackView:View {
    var body: some View {
        VStack(spacing: 35){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍")
                .font(.largeTitle)
            Text("🎺")
                .font(.largeTitle)
            Text("🐼")
                .font(.largeTitle)
        }
    }
}
struct E29Spacing35HStackView:View {
    var body: some View {
        HStack(spacing:35){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍")
                .font(.largeTitle)
            Text("🎺")
                .font(.largeTitle)
            Text("🐼")
                .font(.largeTitle)
        }
    }
}

struct E29multiFontSpacing35VStackView:View {
    var body: some View {
        VStack(alignment: .leading ,spacing: 35){
            Text("🍎🍎🍎🍎")
                .font(.largeTitle)
            Text("🦍🦍🦍")
                .font(.title)
            Text("🎺🎺")
                .font(.headline)
            Text("🐼")
                .font(.caption)
        }
    }
}
struct E29multiFontSpacing35HStackView:View {
    var body: some View {
        HStack(alignment: .bottom, spacing:35){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍")
                .font(.title)
            Text("🎺")
                .font(.headline)
            Text("🐼")
                .font(.caption)
        }
    }
}
struct E29StandardAlignmentGuideView:View {
    var body: some View {
        VStack(alignment: .leading, spacing:35){
            Text("🍎🍎🍎🍎")
                .font(.largeTitle)
                .frame(width: 200,height: 150)
            Text("🦍🦍")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 300,height: 175)
            Text("🎺 🎺")
                .font(.largeTitle)
                .frame(width: 350,height: 200)
            Text("🐼 🐼 🐼")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 150,height: 150)
        }
    }
}
struct E29WidthOnlyChangeAlignmentGuideView:View {
    var body: some View {
        VStack(alignment: .leading, spacing:35){
            Text("🍎🍎🍎🍎")
                .font(.largeTitle)
                .frame(width: 200)
                .border(Color.black)
            Text("🦍🦍")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 300)
                .border(Color.black)
            Text("🎺 🎺")
                .font(.largeTitle)
                .frame(width: 350)
                .border(Color.black)
            Text("🐼 🐼 🐼")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 150)
                .border(Color.black)
        }
    }
}
struct E29AddedAlignmentGuideView:View {
    var body: some View {
        VStack(alignment: .leading, spacing:35){
            Text("🍎🍎🍎🍎")
                .font(.largeTitle)
                .frame(width: 200)
                .border(Color.black)
            Text("🦍🦍")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 300)
                .border(Color.black)
            Text("🎺 🎺")
                .font(.largeTitle)
                .alignmentGuide(.leading, computeValue: { dimension in
                    120.0
                })
                .frame(width: 350)
                .border(Color.black)
            Text("🐼 🐼 🐼")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 150)
                .border(Color.black)
        }
    }
}
struct E29AdjustedAlignmentGuideView:View {
    var body: some View {
        VStack(alignment: .leading, spacing:35){
            Text("🍎🍎🍎🍎")
                .font(.largeTitle)
                .frame(width: 200)
                .border(Color.black)
            Text("🦍🦍")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 300)
                .border(Color.black)
            Text("🎺 🎺")
                .font(.largeTitle)
                .alignmentGuide(.leading, computeValue: { dimension in
                    dimension.width / 7
                })
                .frame(width: 350)
                .border(Color.black)
            Text("🐼 🐼 🐼")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 150)
                .border(Color.black)
        }
    }
}
struct E29AccessedAlignmentValueVStackView:View {
    var body: some View {
        VStack(alignment: .trailing){
            Text("🍎")
                .alignmentGuide(.trailing, computeValue: { dimension in
                    dimension[HorizontalAlignment.leading] + 300
                })
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
            Text("🎺🎺🎺")
                .alignmentGuide(.trailing, computeValue: { dimension in
                    dimension[HorizontalAlignment.trailing] - 30
                })
                .font(.largeTitle)
            Text("🐼🐼🐼🐼")
                .font(.largeTitle)
        }
    }
}
struct E29CustomHStackView:View {
    var body: some View {
        HStack{
            Text("🍎")
                .font(.largeTitle)
            Text("🦍")
                .font(.largeTitle)
            Text("🎺")
                .font(.largeTitle)
            Text("🐼")
                .font(.largeTitle)
        }
    }
}

struct E29CustomedPentaHStackView:View {
    var body: some View {
        HStack(alignment: .e29Penta){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
                .alignmentGuide(.e29Penta, computeValue: { dimension in
                    dimension[VerticalAlignment.bottom]
                })
            Text("🎺🎺")
                .font(.largeTitle)
            Text("🐼")
                .font(.largeTitle)
                .alignmentGuide(.e29Penta, computeValue: { dimension in
                    dimension[VerticalAlignment.top]
                })
        }
    }
}
struct E29CustomedQuarterHStackView:View {
    var body: some View {
        HStack(alignment: .e29Quarter){
            Text("🍎🍎")
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
                .alignmentGuide(.e29Quarter, computeValue: { dimension in
                    dimension[VerticalAlignment.top]
                })
            Text("🎺🎺")
                .font(.largeTitle)
            Text("🐼🐼")
                .font(.largeTitle)
                .alignmentGuide(.e29Quarter, computeValue: { dimension in
                    dimension[VerticalAlignment.bottom]
                })
        }
    }
}
struct E29CrossedStackView:View {
    var body: some View {
        HStack(alignment: .e29Cross,spacing: 35){
            Text("しりとり")
                .font(.largeTitle)

            VStack{
                Text("🍎:りんご")
                    .font(.largeTitle)
                Text("🦍:ゴリラ")
                    .font(.largeTitle)
                    .alignmentGuide(.e29Cross, computeValue: { dimension in
                        dimension[VerticalAlignment.center]
                    })
                Text("🎺:ラッパ")
                    .font(.largeTitle)
                Text("🐼:パンダ")
                    .font(.largeTitle)
                Text("💃:ダンス")
                    .font(.largeTitle)
                Text("🍉:スイカ")
                    .font(.largeTitle)
                    .alignmentGuide(.e29Cross, computeValue: { dimension in
                        dimension[VerticalAlignment.center]
                    })
                Text("🦛:カバ")
                    .font(.largeTitle)
            }
        }
    }
}
struct E29StandardZStackView: View {
    var body: some View {
        ZStack(alignment: .e29Alignment){
            Rectangle()
                .foregroundStyle(Color.green)
                .frame(width: 300, height: 300)
            Circle()
                .foregroundStyle(Color.orange)
                .frame(width: 200, height: 200)
            Capsule()
                .foregroundStyle(Color.red)
                .frame(width: 150, height: 100)
        }
    }
}
struct E29CustomedZStackView: View {
    var body: some View {
        ZStack(alignment: .e29Alignment){
            Rectangle()
                .foregroundStyle(Color.green)
                .alignmentGuide(HorizontalAlignment.e29Horizontal, computeValue: { dimension in
                    dimension[.trailing]
                })
                .alignmentGuide(VerticalAlignment.e29Custom, computeValue: { dimension in
                    dimension[VerticalAlignment.bottom]
                })
                .frame(width: 300, height: 300)
            Circle()
                .foregroundStyle(Color.orange)
                .alignmentGuide(VerticalAlignment.e29Custom, computeValue: { dimension in
                    dimension[VerticalAlignment.top]
                })
                .alignmentGuide(HorizontalAlignment.e29Horizontal, computeValue: { dimension in
                    dimension[HorizontalAlignment.center]
                })
                .frame(width: 200, height: 200)
            Capsule()
                .foregroundStyle(Color.red)
                .alignmentGuide(HorizontalAlignment.e29Horizontal, computeValue: { dimension in
                    dimension[.leading]
                })
                .alignmentGuide(VerticalAlignment.e29Custom, computeValue: { dimension in
                    dimension[.bottom]
                })
                .frame(width: 150, height: 100)
        }
    }
}
struct E29EachCustomedZStackView: View {
    var body: some View {
        ZStack(alignment: .e29Alignment){
            Rectangle()
                .foregroundStyle(Color.green)
                .alignmentGuide(HorizontalAlignment.e29Horizontal, computeValue: { dimension in
                    dimension[.leading]
                })
                .alignmentGuide(VerticalAlignment.e29Custom, computeValue: { dimension in
                    dimension[VerticalAlignment.bottom]
                })
                .frame(width: 300, height: 300)
            Circle()
                .foregroundStyle(Color.orange)
                .alignmentGuide(VerticalAlignment.e29Custom, computeValue: { dimension in
                    dimension[VerticalAlignment.center]
                })
                .alignmentGuide(HorizontalAlignment.e29Horizontal, computeValue: { dimension in
                    dimension[HorizontalAlignment.trailing]
                })
                .frame(width: 200, height: 200)
            Capsule()
                .foregroundStyle(Color.red)
                .alignmentGuide(HorizontalAlignment.e29Horizontal, computeValue: { dimension in
                    dimension[.leading]
                })
                .alignmentGuide(VerticalAlignment.e29Custom, computeValue: { dimension in
                    dimension[.top]
                })
                .frame(width: 150, height: 100)
        }
    }
}
#Preview {
    Essentials29ContentsView()
}
"""

//ポイント
let pointEssentials29 = """
◇ここでポイント①:Stackビューまとめ
◻︎VStack:ビューを縦に並べる
◻︎HStack:ビューを横に並べる
◻︎ZStack:ビューを重ねる
こんだけ藁😆

◇ここでポイント②:配置は正直、
頭で理解して計算とかするよりも、
自分で動かしながらで色々試してみるしかないし、そっちの方が早い
あまり、頭ばっかりでやってると、
・モディファイアの優先順位を見誤る
・ビューの配置で計算通りにいかないと余計な時間を消費する
からね〜〜〜
最近のオープンソースでオブジェクト指向言語は顕著だけど、
・論より証拠
・案ずるより産むが易し
で動かした方が早い

机上デバッグとか論理的にとか、建築で例えるとみたいな人もいるけど、
机上はあくまでお机上だし、動きも具体的にイメージできない人が動かす前から論理的になんて言っても、全ての機能の動きも理論的に網羅もしてない段階で何を論理的に考えるのか不思議だし、実際に有体物を使って犬小屋とか家を作るわけでもなく、バックアップも取れて失敗したら元に戻せるし、プレビューですぐに実行結果がわかるのに、
わざわざ机上で考えるだけ時間の無駄
てかXcodeがそのために、プレビューとかシミュレータを用意してくれてる機能を使わずに頭ばっかりで考えるとか
👉Swiftの旨みを完全に殺してるようなもの
だからこのマガジンの冒頭でゆーたとおり、
何で学ぶのかを考えた方がいいってゆーてるだけ
断言してもいいことなんだけど、
何かのサンプルコードとか機能を知るたびに、
・1を聞いて10を知ろうとする
・じっくり考えて、ちゃんと理解して、それから自分で空を組めるようになって
・ゼロから自分で生み出して初めてコードを実行する
みたいなレガシー言語時代のフェーズ型(ウォーターフォール)みたいな職人像を無責任に抱いてやってる人も多いけど、
・コードなんて動かさないで理解できるわけないし、
・自分でゼロから書くとかやるよりも
多くのサンプルコードにスパスパ触れて
サクサク組み込んでコードをテスト系で動かして早めに沢山失敗してる人の方が
明らかに吸収も理解も上達も早いよ〜〜〜〜
てか、実際の現場では後者の人しか生き残ってないし、続いてない
👉木を見て森を見ずでも、森見て木を見ずもダメ
💃早めに沢山のサンプルコードを実際に動かして1周回るが一番の近道🕺
"""
//URL
let urlEssentials29 = "https://note.com/m_kakudo/n/na9fc340eb9c6"

//ビュー管理構造体
struct ListiOSApp17DevelopmentEssentialsCh29: Identifiable {
    var id: Int
    var title: String
    var view: ViewEnumiOSApp17DevelopmentEssentialsCh29
}
//遷移先の画面を格納する列挙型
enum ViewEnumiOSApp17DevelopmentEssentialsCh29{
    case Sec1
}
//各項目に表示するリスト項目
let dataiOSApp17DevelopmentEssentialsCh29: [ListiOSApp17DevelopmentEssentialsCh29] = [
    ListiOSApp17DevelopmentEssentialsCh29(id: 1, title: essentialsChapter29SubTitle, view: .Sec1),
]
struct iOSApp17DevelopmentEssentialsCh29: View {
    var body: some View {
        VStack {
            Divider()
            List (dataiOSApp17DevelopmentEssentialsCh29) { data in
                self.containedViewiOSApp17DevelopmentEssentialsCh29(dataiOSApp17DevelopmentEssentialsCh29: data)
            }
            .edgesIgnoringSafeArea([.bottom])
        }
        .navigationTitle(essentialsChapter29NavigationTitle)
        .navigationBarTitleDisplayMode(.inline)
    }
    //タップ後に遷移先へ遷移させる関数
    func containedViewiOSApp17DevelopmentEssentialsCh29(dataiOSApp17DevelopmentEssentialsCh29: ListiOSApp17DevelopmentEssentialsCh29) -> AnyView {
        switch dataiOSApp17DevelopmentEssentialsCh29.view {
        case .Sec1:
            return AnyView(NavigationLink (destination: Essentials29()) {
                Text(dataiOSApp17DevelopmentEssentialsCh29.title)
            })
        }
    }
}
#Preview {
    iOSApp17DevelopmentEssentialsCh29()
}

struct Essentials29: View {
    var body: some View {
        VStack{
            TabView {
                Essentials29ContentsView()
                    .tabItem {
                        Image(systemName: contentsImageTab)
                        Text(contentsTextTab)
                    }
                Essentials29Code()
                    .tabItem {
                        Image(systemName: codeImageTab)
                        Text(codeTextTab)
                    }
                Essentials29Points()
                    .tabItem {
                        Image(systemName: pointImageTab)
                        Text(pointTextTab)
                    }
                Essentials29WEB()
                    .tabItem {
                        Image(systemName: webImageTab)
                        Text(webTextTab)
                    }
            }
        }
    }
}
#Preview {
    Essentials29()
}

struct Essentials29Code: View {
    var body: some View {
        ScrollView{
            Text(codeEssentials29)
        }
    }
}
#Preview {
    Essentials29Code()
}
struct Essentials29Points: View {
    var body: some View {
        ScrollView{
            Text(pointEssentials29)
        }
    }
}
#Preview {
    Essentials29Points()
}
struct Essentials29WebView: UIViewRepresentable {
    let searchURL: URL
    func makeUIView(context: Context) -> WKWebView {
        let view = WKWebView()
        let request = URLRequest(url: searchURL)
        view.load(request)
        return view
    }
    func updateUIView(_ uiView: WKWebView, context: Context) {
        
    }
}
struct Essentials29WEB: View {
    private var url:URL = URL(string: urlEssentials29)!
    var body: some View {Essentials29WebView(searchURL: url)
    }
}
#Preview {
    Essentials29WEB()
}
struct Essentials29ContentsView: View {
    var body: some View {
        ScrollView{
            VStack{
                E29StandardVStackView()
                E29TrailingVStackView()
                E29LeadingVStackView()
                E29StandardHStackView()
                E29TopHStackView()
                E29BottomHStackView()
                E29Spacing35VStackView()
                E29Spacing35HStackView()
                E29multiFontSpacing35VStackView()
                E29multiFontSpacing35HStackView()
                E29StandardAlignmentGuideView()
                E29WidthOnlyChangeAlignmentGuideView()
                E29AddedAlignmentGuideView()
                E29AdjustedAlignmentGuideView()
                E29AccessedAlignmentValueVStackView()
                E29CustomHStackView()
                E29CustomedPentaHStackView()
                E29CustomedQuarterHStackView()
                E29CrossedStackView()
                E29StandardZStackView()
                E29CustomedZStackView()
                E29EachCustomedZStackView()
            }
        }
    }
}
struct E29StandardVStackView:View {
    var body: some View {
        VStack{
            Text("🍎")
                .font(.largeTitle)
            Text("🦍")
                .font(.largeTitle)
            Text("🎺")
                .font(.largeTitle)
        }
    }
}
struct E29TrailingVStackView:View {
    var body: some View {
        VStack(alignment: .trailing){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
            Text("🎺🎺🎺")
                .font(.largeTitle)
        }
    }
}
struct E29LeadingVStackView:View {
    var body: some View {
        VStack(alignment: .leading){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
            Text("🎺🎺🎺")
                .font(.largeTitle)
        }
    }
}
struct E29StandardHStackView:View {
    var body: some View {
        HStack{
            Text("🍎")
                .font(.largeTitle)
            Text("🦍")
                .font(.largeTitle)
            Text("🎺")
                .font(.largeTitle)
            Text("🐼")
                .font(.largeTitle)
        }
    }
}
struct E29TopHStackView:View {
    var body: some View {
        HStack(alignment: .top){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
            Text("🎺🎺🎺")
                .font(.largeTitle)
            Text("🐼🐼🐼🐼")
                .font(.largeTitle)
        }
    }
}
struct E29BottomHStackView:View {
    var body: some View {
        HStack(alignment: .bottom){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
            Text("🎺🎺🎺")
                .font(.largeTitle)
            Text("🐼🐼🐼🐼")
                .font(.largeTitle)
        }
    }
}
struct E29Spacing35VStackView:View {
    var body: some View {
        VStack(spacing: 35){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍")
                .font(.largeTitle)
            Text("🎺")
                .font(.largeTitle)
            Text("🐼")
                .font(.largeTitle)
        }
    }
}
struct E29Spacing35HStackView:View {
    var body: some View {
        HStack(spacing:35){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍")
                .font(.largeTitle)
            Text("🎺")
                .font(.largeTitle)
            Text("🐼")
                .font(.largeTitle)
        }
    }
}

struct E29multiFontSpacing35VStackView:View {
    var body: some View {
        VStack(alignment: .leading ,spacing: 35){
            Text("🍎🍎🍎🍎")
                .font(.largeTitle)
            Text("🦍🦍🦍")
                .font(.title)
            Text("🎺🎺")
                .font(.headline)
            Text("🐼")
                .font(.caption)
        }
    }
}
struct E29multiFontSpacing35HStackView:View {
    var body: some View {
        HStack(alignment: .bottom, spacing:35){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍")
                .font(.title)
            Text("🎺")
                .font(.headline)
            Text("🐼")
                .font(.caption)
        }
    }
}
struct E29StandardAlignmentGuideView:View {
    var body: some View {
        VStack(alignment: .leading, spacing:35){
            Text("🍎🍎🍎🍎")
                .font(.largeTitle)
                .frame(width: 200,height: 150)
            Text("🦍🦍")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 300,height: 175)
            Text("🎺 🎺")
                .font(.largeTitle)
                .frame(width: 350,height: 200)
            Text("🐼 🐼 🐼")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 150,height: 150)
        }
    }
}
struct E29WidthOnlyChangeAlignmentGuideView:View {
    var body: some View {
        VStack(alignment: .leading, spacing:35){
            Text("🍎🍎🍎🍎")
                .font(.largeTitle)
                .frame(width: 200)
                .border(Color.black)
            Text("🦍🦍")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 300)
                .border(Color.black)
            Text("🎺 🎺")
                .font(.largeTitle)
                .frame(width: 350)
                .border(Color.black)
            Text("🐼 🐼 🐼")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 150)
                .border(Color.black)
        }
    }
}
struct E29AddedAlignmentGuideView:View {
    var body: some View {
        VStack(alignment: .leading, spacing:35){
            Text("🍎🍎🍎🍎")
                .font(.largeTitle)
                .frame(width: 200)
                .border(Color.black)
            Text("🦍🦍")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 300)
                .border(Color.black)
            Text("🎺 🎺")
                .font(.largeTitle)
                .alignmentGuide(.leading, computeValue: { dimension in
                    120.0
                })
                .frame(width: 350)
                .border(Color.black)
            Text("🐼 🐼 🐼")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 150)
                .border(Color.black)
        }
    }
}
struct E29AdjustedAlignmentGuideView:View {
    var body: some View {
        VStack(alignment: .leading, spacing:35){
            Text("🍎🍎🍎🍎")
                .font(.largeTitle)
                .frame(width: 200)
                .border(Color.black)
            Text("🦍🦍")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 300)
                .border(Color.black)
            Text("🎺 🎺")
                .font(.largeTitle)
                .alignmentGuide(.leading, computeValue: { dimension in
                    dimension.width / 7
                })
                .frame(width: 350)
                .border(Color.black)
            Text("🐼 🐼 🐼")
                .font(.largeTitle)
                .background(Color.gray)
                .frame(width: 150)
                .border(Color.black)
        }
    }
}
struct E29AccessedAlignmentValueVStackView:View {
    var body: some View {
        VStack(alignment: .trailing){
            Text("🍎")
                .alignmentGuide(.trailing, computeValue: { dimension in
                    dimension[HorizontalAlignment.leading] + 300
                })
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
            Text("🎺🎺🎺")
                .alignmentGuide(.trailing, computeValue: { dimension in
                    dimension[HorizontalAlignment.trailing] - 30
                })
                .font(.largeTitle)
            Text("🐼🐼🐼🐼")
                .font(.largeTitle)
        }
    }
}
struct E29CustomHStackView:View {
    var body: some View {
        HStack{
            Text("🍎")
                .font(.largeTitle)
            Text("🦍")
                .font(.largeTitle)
            Text("🎺")
                .font(.largeTitle)
            Text("🐼")
                .font(.largeTitle)
        }
    }
}

struct E29CustomedPentaHStackView:View {
    var body: some View {
        HStack(alignment: .e29Penta){
            Text("🍎")
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
                .alignmentGuide(.e29Penta, computeValue: { dimension in
                    dimension[VerticalAlignment.bottom]
                })
            Text("🎺🎺")
                .font(.largeTitle)
            Text("🐼")
                .font(.largeTitle)
                .alignmentGuide(.e29Penta, computeValue: { dimension in
                    dimension[VerticalAlignment.top]
                })
        }
    }
}
struct E29CustomedQuarterHStackView:View {
    var body: some View {
        HStack(alignment: .e29Quarter){
            Text("🍎🍎")
                .font(.largeTitle)
            Text("🦍🦍")
                .font(.largeTitle)
                .alignmentGuide(.e29Quarter, computeValue: { dimension in
                    dimension[VerticalAlignment.top]
                })
            Text("🎺🎺")
                .font(.largeTitle)
            Text("🐼🐼")
                .font(.largeTitle)
                .alignmentGuide(.e29Quarter, computeValue: { dimension in
                    dimension[VerticalAlignment.bottom]
                })
        }
    }
}
struct E29CrossedStackView:View {
    var body: some View {
        HStack(alignment: .e29Cross,spacing: 35){
            Text("しりとり")
                .font(.largeTitle)

            VStack{
                Text("🍎:りんご")
                    .font(.largeTitle)
                Text("🦍:ゴリラ")
                    .font(.largeTitle)
                    .alignmentGuide(.e29Cross, computeValue: { dimension in
                        dimension[VerticalAlignment.center]
                    })
                Text("🎺:ラッパ")
                    .font(.largeTitle)
                Text("🐼:パンダ")
                    .font(.largeTitle)
                Text("💃:ダンス")
                    .font(.largeTitle)
                Text("🍉:スイカ")
                    .font(.largeTitle)
                    .alignmentGuide(.e29Cross, computeValue: { dimension in
                        dimension[VerticalAlignment.center]
                    })
                Text("🦛:カバ")
                    .font(.largeTitle)
            }
        }
    }
}
struct E29StandardZStackView: View {
    var body: some View {
        ZStack(alignment: .e29Alignment){
            Rectangle()
                .foregroundStyle(Color.green)
                .frame(width: 300, height: 300)
            Circle()
                .foregroundStyle(Color.orange)
                .frame(width: 200, height: 200)
            Capsule()
                .foregroundStyle(Color.red)
                .frame(width: 150, height: 100)
        }
    }
}
struct E29CustomedZStackView: View {
    var body: some View {
        ZStack(alignment: .e29Alignment){
            Rectangle()
                .foregroundStyle(Color.green)
                .alignmentGuide(HorizontalAlignment.e29Horizontal, computeValue: { dimension in
                    dimension[.trailing]
                })
                .alignmentGuide(VerticalAlignment.e29Custom, computeValue: { dimension in
                    dimension[VerticalAlignment.bottom]
                })
                .frame(width: 300, height: 300)
            Circle()
                .foregroundStyle(Color.orange)
                .alignmentGuide(VerticalAlignment.e29Custom, computeValue: { dimension in
                    dimension[VerticalAlignment.top]
                })
                .alignmentGuide(HorizontalAlignment.e29Horizontal, computeValue: { dimension in
                    dimension[HorizontalAlignment.center]
                })
                .frame(width: 200, height: 200)
            Capsule()
                .foregroundStyle(Color.red)
                .alignmentGuide(HorizontalAlignment.e29Horizontal, computeValue: { dimension in
                    dimension[.leading]
                })
                .alignmentGuide(VerticalAlignment.e29Custom, computeValue: { dimension in
                    dimension[.bottom]
                })
                .frame(width: 150, height: 100)
        }
    }
}
struct E29EachCustomedZStackView: View {
    var body: some View {
        ZStack(alignment: .e29Alignment){
            Rectangle()
                .foregroundStyle(Color.green)
                .alignmentGuide(HorizontalAlignment.e29Horizontal, computeValue: { dimension in
                    dimension[.leading]
                })
                .alignmentGuide(VerticalAlignment.e29Custom, computeValue: { dimension in
                    dimension[VerticalAlignment.bottom]
                })
                .frame(width: 300, height: 300)
            Circle()
                .foregroundStyle(Color.orange)
                .alignmentGuide(VerticalAlignment.e29Custom, computeValue: { dimension in
                    dimension[VerticalAlignment.center]
                })
                .alignmentGuide(HorizontalAlignment.e29Horizontal, computeValue: { dimension in
                    dimension[HorizontalAlignment.trailing]
                })
                .frame(width: 200, height: 200)
            Capsule()
                .foregroundStyle(Color.red)
                .alignmentGuide(HorizontalAlignment.e29Horizontal, computeValue: { dimension in
                    dimension[.leading]
                })
                .alignmentGuide(VerticalAlignment.e29Custom, computeValue: { dimension in
                    dimension[.top]
                })
                .frame(width: 150, height: 100)
        }
    }
}
#Preview {
    Essentials29ContentsView()
}

◾️EssentailsExtentsions.swift

import Foundation
import SwiftUI

extension VerticalAlignment{
    private enum E29Pentagon: AlignmentID {
        static func defaultValue(in dimension: ViewDimensions) -> CGFloat {
            return dimension.height / 5
        }
    }
    private enum E29Quarter: AlignmentID {
        static func defaultValue(in dimension: ViewDimensions) -> CGFloat {
            return dimension.height / 4
        }
    }
    private enum E29CrossAlignment: AlignmentID {
        static func defaultValue(in dimension: ViewDimensions) -> CGFloat {
            return dimension[.top]
        }
    }
    private enum E29Custom: AlignmentID{
        static func defaultValue(in dimension: ViewDimensions) -> CGFloat {
            return dimension[VerticalAlignment.center]
        }
    }
    static let e29Penta = VerticalAlignment(E29Pentagon.self)
    static let e29Quarter = VerticalAlignment(E29Quarter.self)
    static let e29Cross = VerticalAlignment(E29CrossAlignment.self)
    static let e29Custom = VerticalAlignment(E29Custom.self)
}

extension HorizontalAlignment {
    enum E29Horizontal: AlignmentID{
        static func defaultValue(in dimension: ViewDimensions) -> CGFloat {
            dimension[HorizontalAlignment.center]
        }
    }
    static let e29Horizontal = HorizontalAlignment(E29Horizontal.self)
}

extension Alignment {
    static let e29Alignment = Alignment(horizontal: .e29Horizontal, vertical: .e29Custom)
}

◾️EssentialsMenu.swift

//フレームワーク
import SwiftUI
import WebKit

//ビュー管理構造体
struct ListiOSApp17DevelopmentEssentials: Identifiable {
    var id: Int
    var title: String
    var view: ViewEnumiOSApp17DevelopmentEssentials
}
//遷移先の画面を格納する列挙型
enum ViewEnumiOSApp17DevelopmentEssentials {
    case Ch1
    //じっくり13で追加
    case Ch2
    //じっくり14で追加
    case Ch3
    //じっくり15で追加
    case Ch4
    //じっくり16で追加
    case Ch5
    //じっくり17で追加
    case Ch6
    //じっくり18で追加
    case Ch7
    //じっくり19で追加
    case Ch8
    //じっくり20、21で追加
    case Ch9
    //じっくり22、23で追加
    case Ch10
    //じっくり24で追加
    case Ch11
    //じっくり25で追加
    case Ch12
    //じっくり26で追加
    case Ch13
    //じっくり27,28で追加
    case Ch14
    //じっくり29で追加
    case Ch15
    //じっくり31で追加
    case Ch16
    //じっくり32で追加
    case Ch17
    //じっくり33で追加
    case Ch18
    //じっくり34で追加
    case Ch19
    //じっくり35で追加
    case Ch20
    //じっくり36で追加
    case Ch21
    //じっくり37で追加
    case Ch22
    //じっくり40で追加
    case Ch23
    //じっくり41で追加
    case Ch24
    //じっくり43で追加
    case Ch25
    //じっくり44で追加
    case Ch26
    //じっくり45で追加
    case Ch27
    //じっくり46で追加
    case Ch28
    //じっくり47で追加
    case Ch29
}
//各項目に表示する文字列
let dataiOSApp17DevelopmentEssentials: [ListiOSApp17DevelopmentEssentials] = [
    ListiOSApp17DevelopmentEssentials(id: 1, title: essentialsChapter1Title, view: .Ch1),
    //じっくり13で追加
    ListiOSApp17DevelopmentEssentials(id: 2, title: essentialsChapter2Title, view: .Ch2),
    //じっくり13で追加
    ListiOSApp17DevelopmentEssentials(id: 3, title: essentialsChapter3Title, view: .Ch3),
    //じっくり15で追加
    ListiOSApp17DevelopmentEssentials(id: 4, title: essentialsChapter4Title, view: .Ch4),
    //じっくり16で追加
    ListiOSApp17DevelopmentEssentials(id: 5, title: essentialsChapter5Title, view: .Ch5),
    //じっくり17で追加
    ListiOSApp17DevelopmentEssentials(id: 6, title: essentialsChapter6Title, view: .Ch6),
    //じっくり18で追加
    ListiOSApp17DevelopmentEssentials(id: 7, title: essentialsChapter7Title, view: .Ch7),
    //じっくり19で追加
    ListiOSApp17DevelopmentEssentials(id: 8, title: essentialsChapter8Title, view: .Ch8),
    //じっくり20、21で追加
    ListiOSApp17DevelopmentEssentials(id: 9, title: essentialsChapter9Title, view: .Ch9),
    //じっくり22、23で追加
    ListiOSApp17DevelopmentEssentials(id: 10, title: essentialsChapter10Title, view: .Ch10),
    //じっくり24で追加
    ListiOSApp17DevelopmentEssentials(id: 11, title: essentialsChapter11Title, view: .Ch11),
    //じっくり25で追加
    ListiOSApp17DevelopmentEssentials(id: 12, title: essentialsChapter12Title, view: .Ch12),
    //じっくり26で追加
    ListiOSApp17DevelopmentEssentials(id: 13, title: essentialsChapter13Title, view: .Ch13),
    //じっくり27,28で追加
    ListiOSApp17DevelopmentEssentials(id: 14, title: essentialsChapter14Title, view: .Ch14),
    //じっくり29で追加
    ListiOSApp17DevelopmentEssentials(id: 15, title: essentialsChapter15Title, view: .Ch15),
    //じっくり31で追加
    ListiOSApp17DevelopmentEssentials(id: 16, title: essentialsChapter16Title, view: .Ch16),
    //じっくり32で追加
    ListiOSApp17DevelopmentEssentials(id: 17, title: essentialsChapter17Title, view: .Ch17),
    //じっくり33で追加
    ListiOSApp17DevelopmentEssentials(id: 18, title: essentialsChapter18Title, view: .Ch18),
    //じっくり34で追加
    ListiOSApp17DevelopmentEssentials(id: 19, title: essentialsChapter19Title, view: .Ch19),
    //じっくり35で追加
    ListiOSApp17DevelopmentEssentials(id: 20, title: essentialsChapter20Title, view: .Ch20),
    //じっくり36で追加
    ListiOSApp17DevelopmentEssentials(id: 21, title: essentialsChapter21Title, view: .Ch21),
    //じっくり37で追加
    ListiOSApp17DevelopmentEssentials(id: 22, title: essentialsChapter22Title, view: .Ch22),
    //じっくり40で追加
    ListiOSApp17DevelopmentEssentials(id: 23, title: essentialsChapter23Title, view: .Ch23),
    //じっくり41で追加
    ListiOSApp17DevelopmentEssentials(id: 24, title: essentialsChapter24Title, view: .Ch24),
    //じっくり43で追加
    ListiOSApp17DevelopmentEssentials(id: 25, title: essentialsChapter25Title, view: .Ch25),
    //じっくり44で追加
    ListiOSApp17DevelopmentEssentials(id: 26, title: essentialsChapter26Title, view: .Ch26),
    //じっくり45で追加
    ListiOSApp17DevelopmentEssentials(id: 27, title: essentialsChapter27Title, view: .Ch27),
    //じっくり46で追加
    ListiOSApp17DevelopmentEssentials(id: 28, title: essentialsChapter28Title, view: .Ch28),
    //じっくり47で追加
    ListiOSApp17DevelopmentEssentials(id: 29, title: essentialsChapter29Title, view: .Ch29),
]

struct iOSApp17DevelopmentEssentials: View {
    var body: some View {
        VStack {
            Divider()
            List (dataiOSApp17DevelopmentEssentials) { data in
                self.containedViewiOSApp17DevelopmentEssentials(dataiOSApp17DevelopmentEssentials: data)
            }
            .edgesIgnoringSafeArea([.bottom])
        }
        .navigationTitle("iOS開発の章目次")
        .navigationBarTitleDisplayMode(.inline)
    }
    //タップ後に遷移先へ遷移させる関数
    func containedViewiOSApp17DevelopmentEssentials(dataiOSApp17DevelopmentEssentials: ListiOSApp17DevelopmentEssentials) -> AnyView {
        switch dataiOSApp17DevelopmentEssentials.view {
        case .Ch1:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh1()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
            //じっくり13で追加
        case .Ch2:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh2()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
            //じっくり13で追加
        case .Ch3:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh3()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
            //じっくり15で追加
        case .Ch4:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh4()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
            //じっくり16で追加
        case .Ch5:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh5()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
            //じっくり17で追加
        case .Ch6:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh6()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
            //じっくり18で追加
        case .Ch7:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh7()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
            //じっくり19で追加
        case .Ch8:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh8()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
            //じっくり20、21で追加
        case .Ch9:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh9()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
            //じっくり22、23で追加
        case .Ch10:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh10()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
            //じっくり24で追加
        case .Ch11:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh11()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
            //じっくり25で追加
        case .Ch12:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh12()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
            //じっくり26で追加
        case .Ch13:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh13()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
            //じっくり27,28で追加
        case .Ch14:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh14()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
            //じっくり29で追加
        case .Ch15:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh15()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
            //じっくり31で追加
        case .Ch16:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh16()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
            //じっくり32で追加
        case .Ch17:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh17()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
            //じっくり33で追加
        case .Ch18:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh18()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
            //じっくり34で追加
        case .Ch19:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh19()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
            //じっくり35で追加
        case .Ch20:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh20()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
            //じっくり36で追加
        case .Ch21:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh21()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
            //じっくり37で追加
        case .Ch22:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh22()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
            //じっくり40で追加
        case .Ch23:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh23()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
            //じっくり41で追加
        case .Ch24:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh24()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
            //じっくり43で追加
        case .Ch25:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh25()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
            //じっくり44で追加
        case .Ch26:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh26()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
            //じっくり45で追加
        case .Ch27:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh27()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
            //じっくり46で追加
        case .Ch28:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh28()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
            //じっくり46で追加
        case .Ch29:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh29()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
        }
    }
}

#Preview {
    iOSApp17DevelopmentEssentials()
}

以上🕺

さてと、あとは温泉行って晩酌して寝よう
みなさんも良い休日を〜〜

この記事が気に入ったらサポートをしてみませんか?