見出し画像

【じっくりSw1ftUI49】実践編19〜第31章 SwiftUIリストとナビゲーションのチュートリアル

先週は、平日昼間の業務で心身ともに疲れ果てていたので、お休みをしちゃいまして、、、申し訳🙇‍♂️🙇‍♀️🙇
それでは約2週間ぶりに〜〜〜

さてと、前回

でやった

リストとナビゲーションの続きについてやってく〜〜〜🕺

毎度、同じように、オイラの学びなんざ要らないって人は、

読めば全部載ってるみたいだからそっち読んだらいいんじゃね?👀
んだば早速、

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

概要としては

前回紹介した機能のコンセプトに基づいた具体的な実践例
を今回はやってくぜ🕺

みたいなことを書いてんね👀💦じゃ、実際に中身を読んでこう

まずは、リストの構造体を用意して〜〜〜

import SwiftUI

struct Essentials31ContentsView: View {
    var body: some View {
        Text("")
    }
}

#Preview {
    Essentials31ContentsView()
}

てな感じの今回用のファイルを用意して、

struct Fruits: Hashable, Codable, Identifiable{
    var id: UUID = UUID()
    var name: String
    var description: String
    var isBool: Bool
    var imageName: String
}

てな感じの構造体を追加🕺

import SwiftUI

struct Fruits: Hashable, Codable, Identifiable{
    var id: UUID = UUID()
    var name: String
    var description: String
    var isBool: Bool
    var imageName: String
}

struct Essentials31ContentsView: View {
    var body: some View {
        Text("")
    }
}

#Preview {
    Essentials31ContentsView()
}

てな感じで、

もちろんまだ何も出てきてないね😛

次にデータクラスを用意して〜〜〜

こーゆー作業はひとつのデータからやらないと失敗した時に手戻りが多くなって面倒くさいので、、、

@Observable class FruitsStore: Identifiable{
    var dwawings: [Fruits] = [
        Fruits(
            name: <#T##String#>,
            description: <#T##String#>,
            isBool: <#T##Bool#>,
            imageName: <#T##String#>
        )
    ]
}

てな感じのコードを

import SwiftUI

struct Fruits: Hashable, Codable, Identifiable{
    var id: UUID = UUID()
    var name: String
    var description: String
    var isBool: Bool
    var imageName: String
}

@Observable class FruitsStore: Identifiable{
    var dwawings: [Fruits] = [
        Fruits(
            name: <#T##String#>,
            description: <#T##String#>,
            isBool: <#T##Bool#>,
            imageName: <#T##String#>
        )
    ]
}

struct Essentials31ContentsView: View {
    var body: some View {
        Text("")
    }
}

#Preview {
    Essentials31ContentsView()
}

てな感じではめ込んでみても、

もちろん、データクラスの中に何もデータがないからエラー🤣

で、どーやら画像をアセットに嵌め込む必要がそろそろありそうだし、そろそろやってもいいかなあって感じなので、

みたいな感じで検索して、
テケトーにりんごの画像を切り抜いたら
デスクトップにでけたスクショの名前を変更して
Xcode左下のAssetsをクリック
てな感じでさっきの画像を取り込み
@Observable class FruitsStore: Identifiable{
    var dwawings: [Fruits] = [
        Fruits(
            name: "りんご",
            description: "美味しいりんご",
            isBool: true,
            imageName: "りんごちゃん"
        )
    ]
}

てな感じでさっきのコードを変更

コンテントビューを編集してく〜〜〜

今んとこ

import SwiftUI

struct Fruits: Hashable, Codable, Identifiable{
    var id: UUID = UUID()
    var name: String
    var description: String
    var isBool: Bool
    var imageName: String
}

@Observable class FruitsStore: Identifiable{
    var dwawings: [Fruits] = [
        Fruits(
            name: "りんご",
            description: "美味しいりんご",
            isBool: true,
            imageName: "りんごちゃん"
        )
    ]
}

struct Essentials31ContentsView: View {
    @State var fruitsStore: FruitsStore = FruitsStore()
    
    var body: some View {
        Text("")
    }
}

#Preview {
    Essentials31ContentsView()
}

てな感じ。

でもって、リストをコンテントビューにセットする用のビューが必要そうなんで

struct FruitsListCell: View {
    var fruits: Fruits
    
    var body: some View{
        HStack{
            Image(fruits.imageName)
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width: 100, height: 75)
            Text(fruits.name)
        }
    }
}

てな感じでビューを追加して、

コンテントビューにさらにこのリストセルビューを組み込み〜〜〜

struct Essentials31ContentsView: View {
    @State var fruitsStore: FruitsStore = FruitsStore()
    
    var body: some View {
        List{
            ForEach($fruitsStore.dwawings, id: \.self){
                $fruitsMenu in FruitsListCell(fruits: fruitsMenu)
            }
        }
    }
}

てな感じでコードをセットすると〜〜〜

まずはリストがひとつできたので〜〜〜

調子に乗って、みかんとバナナとブドウと桃を追加してく〜〜〜

てな感じで、さっきと同じ要領で画像をセット〜〜〜
@Observable class FruitsStore: Identifiable{
    var dwawings: [Fruits] = [
        Fruits(
            name: "りんご",
            description: "美味しいりんご",
            isBool: true,
            imageName: "りんごちゃん"
        ),
        Fruits(
            name: "みかん",
            description: "さっぱりみかん",
            isBool: false,
            imageName: "みかんちゃん"
        ),
        Fruits(
            name: "バナナ",
            description: "鮮度抜群のバナナ",
            isBool: false,
            imageName: "バナナさん"
        ),
        Fruits(
            name: "葡萄",
            description: "今が旬な葡萄",
            isBool: false,
            imageName: "ブドウ先輩"
        ),
        Fruits(
            name: "桃",
            description: "いつでも食べたい桃",
            isBool: false,
            imageName: "ピーチ姫笑"
        )
    ]
}

てな感じでデータクラスを変更して〜〜〜〜

リスト項目はでけた〜〜〜〜🕺

お次はリストをタップすると詳細に飛ぶ画面を作る〜〜〜

の前に、他のビューファイルとの関係もややこしくなりそうなので、一旦コードをここで

import SwiftUI

struct E31Fruits: Hashable, Codable, Identifiable{
    var id: UUID = UUID()
    var name: String
    var description: String
    var isBool: Bool
    var imageName: String
}

@Observable class E31FruitsStore: Identifiable{
    var dwawings: [E31Fruits] = [
        E31Fruits(
            name: "りんご",
            description: "美味しいりんご",
            isBool: true,
            imageName: "りんごちゃん"
        ),
        E31Fruits(
            name: "みかん",
            description: "さっぱりみかん",
            isBool: false,
            imageName: "みかんちゃん"
        ),
        E31Fruits(
            name: "バナナ",
            description: "鮮度抜群のバナナ",
            isBool: false,
            imageName: "バナナさん"
        ),
        E31Fruits(
            name: "葡萄",
            description: "今が旬な葡萄",
            isBool: false,
            imageName: "ブドウ先輩"
        ),
        E31Fruits(
            name: "桃",
            description: "いつでも食べたい桃",
            isBool: false,
            imageName: "ピーチ姫笑"
        )
    ]
}

struct Essentials31ContentsView: View {
    @State var fruitsStore: E31FruitsStore = E31FruitsStore()
    
    var body: some View {
        List{
            ForEach($fruitsStore.dwawings, id: \.self){
                $fruitsMenu in E31FruitsListCell(fruits: fruitsMenu)
            }
        }
    }
}

struct E31FruitsListCell: View {
    var fruits: E31Fruits
    
    var body: some View{
        HStack{
            Image(fruits.imageName)
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width: 100, height: 75)
            Text(fruits.name)
        }
    }
}



#Preview {
    Essentials31ContentsView()
}

てな感じで今回用とわかるように、

E31を先頭に追加笑💦

struct E31FruitsDescriptionView: View {
    let selectedFruits: E31Fruits
    var body: some View {
        Form{
            Section(header: Text("ひと言")){
                Image(selectedFruits.imageName)
                    .resizable()
                    .presentationCornerRadius(13.5)
                    .aspectRatio(contentMode: .fit)
                    .padding()
                Text(selectedFruits.name)
                    .font(.headline)
                Text(selectedFruits.description)
                    .font(.largeTitle)
                HStack{
                    Text("在庫あり").font(.headline)
                    Spacer()
                    Image(systemName: selectedFruits.isBool ? "checkmark.circle" : "xmark.circle")
                }
            }
        }
    }
}

#Preview {
    E31FruitsDescriptionView(selectedFruits: E31FruitsStore().dwawings.first!)
}

てな感じでコードを追加して〜〜〜

てな感じで詳細ビューもでけた〜〜〜

ナビゲーションスタックとナビゲーションリンクを追加してく〜〜〜

struct Essentials31ContentsView: View {
    @State var fruitsStore: E31FruitsStore = E31FruitsStore()
    
    var body: some View {
        NavigationStack{
        List{
            ForEach($fruitsStore.dwawings, id: \.self){
                $fruitsMenu in
                NavigationLink(value: fruitsMenu){
                    E31FruitsListCell(fruits: fruitsMenu)
                }
            }
            }
        }
        .navigationDestination(for: E31Fruits.self){
            fruits in
            E31FruitsDescriptionView(selectedFruits: fruits)
        }
    }
}

てな感じで、コードを編集して、

リンクは追加できた様子だけど、、、

このままだとプレビューで動かないのと、ここから先はちょっと毛色が違うのでここで、

import SwiftUI
import WebKit

//タイトル
let essentialsChapter31NavigationTitle = "第31章"
let essentialsChapter31Title = "第31章 SwiftUIリストとナビゲーションのチュートリアル"
let essentialsChapter31SubTitle = "第1節 SwiftUIリストとナビゲーションのチュートリアル"

//コード
let codeEssentials31 = """

"""

//ポイント
let pointEssentials31 = """

"""
//URL
let urlEssentials31 = "https://note.com/m_kakudo/n/n7332d17d5d9a"

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

struct Essentials31: View {
    var body: some View {
        VStack{
            TabView {
                Essentials31ContentsView()
                    .tabItem {
                        Image(systemName: contentsImageTab)
                        Text(contentsTextTab)
                    }
                Essentials31Code()
                    .tabItem {
                        Image(systemName: codeImageTab)
                        Text(codeTextTab)
                    }
                Essentials31Points()
                    .tabItem {
                        Image(systemName: pointImageTab)
                        Text(pointTextTab)
                    }
                Essentials31WEB()
                    .tabItem {
                        Image(systemName: webImageTab)
                        Text(webTextTab)
                    }
            }
        }
    }
}
#Preview {
    Essentials31()
}

struct Essentials31Code: View {
    var body: some View {
        ScrollView{
            Text(codeEssentials31)
        }
    }
}
#Preview {
    Essentials31Code()
}
struct Essentials31Points: View {
    var body: some View {
        ScrollView{
            Text(pointEssentials31)
        }
    }
}
#Preview {
    Essentials31Points()
}
struct Essentials31WebView: 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 Essentials31WEB: View {
    private var url:URL = URL(string: urlEssentials31)!
    var body: some View {Essentials31WebView(searchURL: url)
    }
}
#Preview {
    Essentials31WEB()
}

struct E31Fruits: Hashable, Codable, Identifiable{
    var id: UUID = UUID()
    var name: String
    var description: String
    var isBool: Bool
    var imageName: String
}

@Observable class E31FruitsStore: Identifiable{
    var dwawings: [E31Fruits] = [
        E31Fruits(
            name: "りんご",
            description: "美味しいりんご",
            isBool: true,
            imageName: "りんごちゃん"
        ),
        E31Fruits(
            name: "みかん",
            description: "さっぱりみかん",
            isBool: false,
            imageName: "みかんちゃん"
        ),
        E31Fruits(
            name: "バナナ",
            description: "鮮度抜群のバナナ",
            isBool: false,
            imageName: "バナナさん"
        ),
        E31Fruits(
            name: "葡萄",
            description: "今が旬な葡萄",
            isBool: false,
            imageName: "ブドウ先輩"
        ),
        E31Fruits(
            name: "桃",
            description: "いつでも食べたい桃",
            isBool: false,
            imageName: "ピーチ姫笑"
        )
    ]
}

struct Essentials31ContentsView: View {
    @State var fruitsStore: E31FruitsStore = E31FruitsStore()
    
    var body: some View {
        NavigationStack{
        List{
            ForEach($fruitsStore.dwawings, id: \.self){
                $fruitsMenu in
                NavigationLink(value: fruitsMenu){
                    E31FruitsListCell(fruits: fruitsMenu)
                }
            }
            }
        }
        .navigationDestination(for: E31Fruits.self){
            fruits in
            E31FruitsDescriptionView(selectedFruits: fruits)
        }
    }
}

struct E31FruitsListCell: View {
    var fruits: E31Fruits
    
    var body: some View{
        HStack{
            Image(fruits.imageName)
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width: 100, height: 75)
            Text(fruits.name)
        }
    }
}

struct E31FruitsDescriptionView: View {
    let selectedFruits: E31Fruits
    var body: some View {
        Form{
            Section(header: Text("ひと言")){
                Image(selectedFruits.imageName)
                    .resizable()
                    .presentationCornerRadius(13.5)
                    .aspectRatio(contentMode: .fit)
                    .padding()
                Text(selectedFruits.name)
                    .font(.headline)
                Text(selectedFruits.description)
                    .font(.largeTitle)
                HStack{
                    Text("在庫あり").font(.headline)
                    Spacer()
                    Image(systemName: selectedFruits.isBool ? "checkmark.circle" : "xmark.circle")
                }
            }
        }
    }
}

#Preview {
    Essentials31ContentsView()
}

#Preview {
    E31FruitsDescriptionView(selectedFruits: E31FruitsStore().dwawings.first!)
}

てな感じで、記事公開後でやってる雛型を追加して、コンテントビューから実行してみると、、、

葡萄をタップ
てな感じでブドウ先輩の解説が出てきた〜〜〜

新しい果物を追加するビューを作る〜〜〜

struct E31AddFruitsView: View {
    @State var fruitsStore: E31FruitsStore
    @State private var isBool = false
    @State private var fruitsName = ""
    @State private description: String = ""
    
    var body: some View {
        
    }
}

#Preview {
    E31AddFruitsView(fruitsStore: E31FruitsStore())
}

てな感じで追加すると、

てな感じでエラーになってるんだけど、

これはまだ、完成してないので静的プログラミング言語では当たり前の話なので、ここでは気にしない。

ここでポイント①:エラー拒否症候群な人って、、、

実は、静的プログラミングの学習に向かない人が多いんだよね〜〜〜

ここに関しては、

みたいな感じで必要な予約語とビューをテケトーに配置してあげれば

エラーは解消するんだけど、エラーを解消するためだけにまだコードとの途中の段階でVStackを別に追加する必要はないし、

ここも解消はすんだけど、

余計な要らないビューをエラー解消のためだけに中途半端に、安易に追加しちゃうと、

本来は未完成なコードなのに、エラーが出てないから、
どこが未完成なのかわからなくなる

からね。

👉エラーが出てるのはなぜかを理解するのは大事だが、
いちいち、一喜一憂する必要なし

さてと、余計なVStackは削除した状態でエラー出まくってる状態に戻して、

てな感じ

データ追加ビューを追加〜〜〜

struct E31FruitsInputView: View {
    var menu: String
    @Binding var fruitsInput: String
    var body: some View {
        VStack(alignment: HorizontalAlignment.leading){
            Text(menu)
                .font(.title)
            TextField("\(menu)を入力してください。",text: $fruitsInput)
                .textFieldStyle(RoundedBorderTextFieldStyle())
        }
        .padding()
    }
}

その上で、さっきのエラーを吐き出してるビューを編集〜〜〜

struct E31AddFruitsView: View {
    @State var fruitsStore: E31FruitsStore
    @State private var isBool = false
    @State private var fruitsName = ""
    @State private var description: String = ""
    
    var body: some View {
        Form{
            Section(header: Text("詳細")){
                Image(systemName: "apple.logo")
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .padding()
                
                E31FruitsInputView(menu: "果物", fruitsInput: $fruitsName)
                E31FruitsInputView(menu: "ひと言", fruitsInput: $description)
                Toggle(isOn: $isBool){
                    Text("在庫")
                        .font(.headline)
                }
                .padding()
            }
            Button(action: addNewFruitsMenu){
                Text("品物追加")
            }
        }
    }
}
てな感じで、プレビューの箇所についてはエラーが解消したんだけど、、、
もちろん、まだアクションに入れてる関数が存在してないので〜〜〜
今度はここがエラー

ここは次に、それ用の関数を作ってあげればいいだけなので〜〜〜

    func addNewFruitsMenu(){
        
    }

を追加しただけで、

てな感じで、まずはさっきのエラーは解消
struct E31AddFruitsView: View {
    @State var fruitsStore: E31FruitsStore
    @State private var isBool = false
    @State private var fruitsName = ""
    @State private var description: String = ""
    
    var body: some View {
        Form{
            Section(header: Text("詳細")){
                Image(systemName: "apple.logo")
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .padding()
                
                E31FruitsInputView(menu: "果物", fruitsInput: $fruitsName)
                E31FruitsInputView(menu: "ひと言", fruitsInput: $description)
                Toggle(isOn: $isBool){
                    Text("在庫")
                        .font(.headline)
                }
                .padding()
            }
            Button(action: addNewFruitsMenu){
                Text("品物追加")
            }
        }
    }
    
    func addNewFruitsMenu(){
        let newFruitsMenu = E31Fruits(
            id: UUID(),
            name: fruitsName,
            description: description,
            isBool: isBool,
            imageName: "りんごちゃん"
        )
        
        fruitsStore.dwawings.append(newFruitsMenu)
    }
}

てな感じで関数の中身を追加して〜〜〜

追加用の画面も出来上がり〜〜〜

大元のリストを移動と削除ができるように〜〜〜

struct Essentials31ContentsView: View {
    @State var fruitsStore: E31FruitsStore = E31FruitsStore()
    @State private var fruitsStackPath = NavigationPath()

    var body: some View {
        NavigationStack(path: $fruitsStackPath){
            List{
                ForEach($fruitsStore.dwawings, id: \.self){
                    $fruitsMenu in
                    NavigationLink(value: fruitsMenu){
                        E31FruitsListCell(fruits: fruitsMenu)
                    }
                }
                .onDelete(perform: deletedMenu)
                .onMove(perform: movedMenu)
            }
            .navigationDestination(for:E31Fruits.self){
                fruitsMenu in
                E31FruitsDescriptionView(selectedFruits: fruitsMenu)
            }
            .navigationDestination(for: String.self){ _ in
                E31AddFruitsView(fruitsStore: fruitsStore ,path:
                                $fruitsStackPath)
            }
            .navigationTitle(Text("新商品"))
            .toolbar{
                ToolbarItem(placement:.navigationBarLeading){
                    NavigationLink(value: "追加"){
                        Text("追加")
                    }
                }
                ToolbarItem(placement: .navigationBarTrailing){
                    EditButton()
                }
            }
        }
    }
    func deletedMenu(at offset:IndexSet){
        fruitsStore.dwawings.remove(atOffsets: offset)
    }
    func movedMenu(from source: IndexSet, to destionation: Int){
        fruitsStore.dwawings.move(fromOffsets: source, toOffset: destionation)
    }
}

てな感じに書き換え〜〜〜

削除は〜〜〜
できるようになったので〜〜〜
シミュレータで移動も出来たことは確認でけた〜〜〜〜

バインディングで追加ビューとも連携させて〜〜〜

struct E31AddFruitsView: View {
    @State var fruitsStore: E31FruitsStore
    @State private var isBool = false
    @State private var fruitsName = ""
    @State private var description: String = ""
    @Binding var path: NavigationPath

    var body: some View {
        Form{
            Section(header: Text("詳細")){
                Image(systemName: "apple.logo")
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .padding()

                E31FruitsInputView(menu: "果物", fruitsInput: $fruitsName)
                E31FruitsInputView(menu: "ひと言", fruitsInput: $description)
                Toggle(isOn: $isBool){
                    Text("在庫")
                        .font(.headline)
                }
                .padding()
            }
            Button(action: addNewFruitsMenu){
                Text("品物追加")
            }
        }
    }

    func addNewFruitsMenu(){
        let newFruitsMenu = E31Fruits(
            id: UUID(),
            name: fruitsName,
            description: description,
            isBool: isBool,
            imageName: "りんごちゃん"
        )

        fruitsStore.dwawings.append(newFruitsMenu)
        path.removeLast()
    }
}

てな感じで〜〜〜

てな感じでコメントアウトして〜〜〜
Editも表示されたので、タップしたところ〜〜〜
左上の追加ボタンをタップして、
てな感じで記入して、品物追加をタップすると
追加されたので、タップすると、、、
詳細もできた〜〜〜

とりあえず今回も以上かな笑🧐

今回のコードまとめ

struct E31Fruits: Hashable, Codable, Identifiable{
    var id: UUID = UUID()
    var name: String
    var description: String
    var isBool: Bool
    var imageName: String
}

@Observable class E31FruitsStore: Identifiable{
    var dwawings: [E31Fruits] = [
        E31Fruits(
            name: "りんご",
            description: "美味しいりんご",
            isBool: true,
            imageName: "りんごちゃん"
        ),
        E31Fruits(
            name: "みかん",
            description: "さっぱりみかん",
            isBool: false,
            imageName: "みかんちゃん"
        ),
        E31Fruits(
            name: "バナナ",
            description: "鮮度抜群のバナナ",
            isBool: false,
            imageName: "バナナさん"
        ),
        E31Fruits(
            name: "葡萄",
            description: "今が旬な葡萄",
            isBool: false,
            imageName: "ブドウ先輩"
        ),
        E31Fruits(
            name: "桃",
            description: "いつでも食べたい桃",
            isBool: false,
            imageName: "ピーチ姫笑"
        )
    ]
}

struct Essentials31ContentsView: View {
    @State var fruitsStore: E31FruitsStore = E31FruitsStore()
    @State private var fruitsStackPath = NavigationPath()

    var body: some View {
        NavigationStack(path: $fruitsStackPath){
            List{
                ForEach($fruitsStore.dwawings, id: \.self){
                    $fruitsMenu in
                    NavigationLink(value: fruitsMenu){
                        E31FruitsListCell(fruits: fruitsMenu)
                    }
                }
                .onDelete(perform: deletedMenu)
                .onMove(perform: movedMenu)
            }
            .navigationDestination(for:E31Fruits.self){
                fruitsMenu in
                E31FruitsDescriptionView(selectedFruits: fruitsMenu)
            }
            .navigationDestination(for: String.self){ _ in
                E31AddFruitsView(fruitsStore: fruitsStore ,path:
                                $fruitsStackPath)
            }
            .navigationTitle(Text("新商品"))
            .toolbar{
                ToolbarItem(placement:.navigationBarLeading){
                    NavigationLink(value: "追加"){
                        Text("追加")
                    }
                }
                ToolbarItem(placement: .navigationBarTrailing){
                    EditButton()
                }
            }
        }
    }
    func deletedMenu(at offset:IndexSet){
        fruitsStore.dwawings.remove(atOffsets: offset)
    }
    func movedMenu(from source: IndexSet, to destionation: Int){
        fruitsStore.dwawings.move(fromOffsets: source, toOffset: destionation)
    }
}

struct E31FruitsListCell: View {
    var fruits: E31Fruits

    var body: some View{
        HStack{
            Image(fruits.imageName)
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width: 100, height: 75)
            Text(fruits.name)
        }
    }
}

struct E31FruitsDescriptionView: View {
    let selectedFruits: E31Fruits
    var body: some View {
        Form{
            Section(header: Text("ひと言")){
                Image(selectedFruits.imageName)
                    .resizable()
                    .presentationCornerRadius(13.5)
                    .aspectRatio(contentMode: .fit)
                    .padding()
                Text(selectedFruits.name)
                    .font(.headline)
                Text(selectedFruits.description)
                    .font(.largeTitle)
                HStack{
                    Text("在庫あり").font(.headline)
                    Spacer()
                    Image(systemName: selectedFruits.isBool ? "checkmark.circle" : "xmark.circle")
                }
            }
        }
    }
}

struct E31AddFruitsView: View {
    @State var fruitsStore: E31FruitsStore
    @State private var isBool = false
    @State private var fruitsName = ""
    @State private var description: String = ""
    @Binding var path: NavigationPath

    var body: some View {
        Form{
            Section(header: Text("詳細")){
                Image(systemName: "apple.logo")
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .padding()

                E31FruitsInputView(menu: "果物", fruitsInput: $fruitsName)
                E31FruitsInputView(menu: "ひと言", fruitsInput: $description)
                Toggle(isOn: $isBool){
                    Text("在庫")
                        .font(.headline)
                }
                .padding()
            }
            Button(action: addNewFruitsMenu){
                Text("品物追加")
            }
        }
    }

    func addNewFruitsMenu(){
        let newFruitsMenu = E31Fruits(
            id: UUID(),
            name: fruitsName,
            description: description,
            isBool: isBool,
            imageName: "りんごちゃん"
        )

        fruitsStore.dwawings.append(newFruitsMenu)
        path.removeLast()
    }
}

struct E31FruitsInputView: View {
    var menu: String
    @Binding var fruitsInput: String

    var body: some View {
        VStack(alignment: HorizontalAlignment.leading){
            Text(menu)
                .font(.title)
            TextField("\(menu)を入力してください。",text: $fruitsInput)
                .textFieldStyle(RoundedBorderTextFieldStyle())
        }
        .padding()
    }
}

#Preview {
    Essentials31ContentsView()
}

#Preview {
    E31FruitsDescriptionView(selectedFruits: E31FruitsStore().dwawings.first!)
}
/*不要なのでコメントアウト
 #Preview {
 E31AddFruitsView(fruitsStore: E31FruitsStore())
 }
 */

Apple公式

さてと、次回は

第32章 NavigationSplitView を使用した SwiftUI での複数列ナビゲーション

をやってく🕺

記事公開後、

いつもどおり、

でやった操作を〜〜〜

前回同様、ツールバーが消えてる👀
てな
てな
感じ

サンプルコード

◾️Essentials31.swift

import SwiftUI
import WebKit

//タイトル
let essentialsChapter31NavigationTitle = "第31章"
let essentialsChapter31Title = "第31章 SwiftUIリストとナビゲーションのチュートリアル"
let essentialsChapter31SubTitle = "第1節 SwiftUIリストとナビゲーションのチュートリアル"

//コード
let codeEssentials31 = """
struct E31Fruits: Hashable, Codable, Identifiable{
    var id: UUID = UUID()
    var name: String
    var description: String
    var isBool: Bool
    var imageName: String
}

@Observable class E31FruitsStore: Identifiable{
    var dwawings: [E31Fruits] = [
        E31Fruits(
            name: "りんご",
            description: "美味しいりんご",
            isBool: true,
            imageName: "りんごちゃん"
        ),
        E31Fruits(
            name: "みかん",
            description: "さっぱりみかん",
            isBool: false,
            imageName: "みかんちゃん"
        ),
        E31Fruits(
            name: "バナナ",
            description: "鮮度抜群のバナナ",
            isBool: false,
            imageName: "バナナさん"
        ),
        E31Fruits(
            name: "葡萄",
            description: "今が旬な葡萄",
            isBool: false,
            imageName: "ブドウ先輩"
        ),
        E31Fruits(
            name: "桃",
            description: "いつでも食べたい桃",
            isBool: false,
            imageName: "ピーチ姫笑"
        )
    ]
}

struct Essentials31ContentsView: View {
    @State var fruitsStore: E31FruitsStore = E31FruitsStore()
    @State private var fruitsStackPath = NavigationPath()

    var body: some View {
        NavigationStack(path: $fruitsStackPath){
            List{
                ForEach($fruitsStore.dwawings, id: \\.self){
                    $fruitsMenu in
                    NavigationLink(value: fruitsMenu){
                        E31FruitsListCell(fruits: fruitsMenu)
                    }
                }
                .onDelete(perform: deletedMenu)
                .onMove(perform: movedMenu)
            }
            .navigationDestination(for:E31Fruits.self){
                fruitsMenu in
                E31FruitsDescriptionView(selectedFruits: fruitsMenu)
            }
            .navigationDestination(for: String.self){ _ in
                E31AddFruitsView(fruitsStore: fruitsStore ,path:
                                $fruitsStackPath)
            }
            .navigationTitle(Text("新商品"))
            .toolbar{
                ToolbarItem(placement:.navigationBarLeading){
                    NavigationLink(value: "追加"){
                        Text("追加")
                    }
                }
                ToolbarItem(placement: .navigationBarTrailing){
                    EditButton()
                }
            }
        }
    }
    func deletedMenu(at offset:IndexSet){
        fruitsStore.dwawings.remove(atOffsets: offset)
    }
    func movedMenu(from source: IndexSet, to destionation: Int){
        fruitsStore.dwawings.move(fromOffsets: source, toOffset: destionation)
    }
}

struct E31FruitsListCell: View {
    var fruits: E31Fruits

    var body: some View{
        HStack{
            Image(fruits.imageName)
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width: 100, height: 75)
            Text(fruits.name)
        }
    }
}

struct E31FruitsDescriptionView: View {
    let selectedFruits: E31Fruits
    var body: some View {
        Form{
            Section(header: Text("ひと言")){
                Image(selectedFruits.imageName)
                    .resizable()
                    .presentationCornerRadius(13.5)
                    .aspectRatio(contentMode: .fit)
                    .padding()
                Text(selectedFruits.name)
                    .font(.headline)
                Text(selectedFruits.description)
                    .font(.largeTitle)
                HStack{
                    Text("在庫あり").font(.headline)
                    Spacer()
                    Image(systemName: selectedFruits.isBool ? "checkmark.circle" : "xmark.circle")
                }
            }
        }
    }
}

struct E31AddFruitsView: View {
    @State var fruitsStore: E31FruitsStore
    @State private var isBool = false
    @State private var fruitsName = ""
    @State private var description: String = ""
    @Binding var path: NavigationPath

    var body: some View {
        Form{
            Section(header: Text("詳細")){
                Image(systemName: "apple.logo")
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .padding()

                E31FruitsInputView(menu: "果物", fruitsInput: $fruitsName)
                E31FruitsInputView(menu: "ひと言", fruitsInput: $description)
                Toggle(isOn: $isBool){
                    Text("在庫")
                        .font(.headline)
                }
                .padding()
            }
            Button(action: addNewFruitsMenu){
                Text("品物追加")
            }
        }
    }

    func addNewFruitsMenu(){
        let newFruitsMenu = E31Fruits(
            id: UUID(),
            name: fruitsName,
            description: description,
            isBool: isBool,
            imageName: "りんごちゃん"
        )

        fruitsStore.dwawings.append(newFruitsMenu)
        path.removeLast()
    }
}

struct E31FruitsInputView: View {
    var menu: String
    @Binding var fruitsInput: String

    var body: some View {
        VStack(alignment: HorizontalAlignment.leading){
            Text(menu)
                .font(.title)
            TextField("\\(menu)を入力してください。",text: $fruitsInput)
                .textFieldStyle(RoundedBorderTextFieldStyle())
        }
        .padding()
    }
}

#Preview {
    Essentials31ContentsView()
}

#Preview {
    E31FruitsDescriptionView(selectedFruits: E31FruitsStore().dwawings.first!)
}
/*不要なのでコメントアウト
 #Preview {
 E31AddFruitsView(fruitsStore: E31FruitsStore())
 }
 */
"""

//ポイント
let pointEssentials31 = """
エラー拒否症候群な人って、、、
実は、静的プログラミングの学習に向かない人が多いんだよね〜〜〜
ここに関しては、必要な予約語とビューをテケトーに配置してあげればエラーは解消するんだけど、エラーを解消するためだけにまだコードとの途中の段階でVStackを別に追加する必要はないし、解消はすんだけど、余計な要らないビューをエラー解消のためだけに中途半端に、安易に追加しちゃうと、
本来は未完成なコードなのに、エラーが出てないから、どこが未完成なのかわからなくなる
からね。
👉エラーが出てるのはなぜかを理解するのは大事だが、いちいち、一喜一憂する必要なし
"""
//URL
let urlEssentials31 = "https://note.com/m_kakudo/n/n2b702a0b2ab2"

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

struct Essentials31: View {
    var body: some View {
        VStack{
            TabView {
                Essentials31ContentsView()
                    .tabItem {
                        Image(systemName: contentsImageTab)
                        Text(contentsTextTab)
                    }
                Essentials31Code()
                    .tabItem {
                        Image(systemName: codeImageTab)
                        Text(codeTextTab)
                    }
                Essentials31Points()
                    .tabItem {
                        Image(systemName: pointImageTab)
                        Text(pointTextTab)
                    }
                Essentials31WEB()
                    .tabItem {
                        Image(systemName: webImageTab)
                        Text(webTextTab)
                    }
            }
        }
    }
}
#Preview {
    Essentials31()
}

struct Essentials31Code: View {
    var body: some View {
        ScrollView{
            Text(codeEssentials31)
        }
    }
}
#Preview {
    Essentials31Code()
}
struct Essentials31Points: View {
    var body: some View {
        ScrollView{
            Text(pointEssentials31)
        }
    }
}
#Preview {
    Essentials31Points()
}
struct Essentials31WebView: 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 Essentials31WEB: View {
    private var url:URL = URL(string: urlEssentials31)!
    var body: some View {Essentials31WebView(searchURL: url)
    }
}
#Preview {
    Essentials31WEB()
}
 
struct E31Fruits: Hashable, Codable, Identifiable{
    var id: UUID = UUID()
    var name: String
    var description: String
    var isBool: Bool
    var imageName: String
}

@Observable class E31FruitsStore: Identifiable{
    var dwawings: [E31Fruits] = [
        E31Fruits(
            name: "りんご",
            description: "美味しいりんご",
            isBool: true,
            imageName: "りんごちゃん"
        ),
        E31Fruits(
            name: "みかん",
            description: "さっぱりみかん",
            isBool: false,
            imageName: "みかんちゃん"
        ),
        E31Fruits(
            name: "バナナ",
            description: "鮮度抜群のバナナ",
            isBool: false,
            imageName: "バナナさん"
        ),
        E31Fruits(
            name: "葡萄",
            description: "今が旬な葡萄",
            isBool: false,
            imageName: "ブドウ先輩"
        ),
        E31Fruits(
            name: "桃",
            description: "いつでも食べたい桃",
            isBool: false,
            imageName: "ピーチ姫笑"
        )
    ]
}

struct Essentials31ContentsView: View {
    @State var fruitsStore: E31FruitsStore = E31FruitsStore()
    @State private var fruitsStackPath = NavigationPath()

    var body: some View {
        NavigationStack(path: $fruitsStackPath){
            List{
                ForEach($fruitsStore.dwawings, id: \.self){
                    $fruitsMenu in
                    NavigationLink(value: fruitsMenu){
                        E31FruitsListCell(fruits: fruitsMenu)
                    }
                }
                .onDelete(perform: deletedMenu)
                .onMove(perform: movedMenu)
            }
            .navigationDestination(for:E31Fruits.self){
                fruitsMenu in
                E31FruitsDescriptionView(selectedFruits: fruitsMenu)
            }
            .navigationDestination(for: String.self){ _ in
                E31AddFruitsView(fruitsStore: fruitsStore ,path:
                                $fruitsStackPath)
            }
            .navigationTitle(Text("新商品"))
            .toolbar{
                ToolbarItem(placement:.navigationBarLeading){
                    NavigationLink(value: "追加"){
                        Text("追加")
                    }
                }
                ToolbarItem(placement: .navigationBarTrailing){
                    EditButton()
                }
            }
        }
    }
    func deletedMenu(at offset:IndexSet){
        fruitsStore.dwawings.remove(atOffsets: offset)
    }
    func movedMenu(from source: IndexSet, to destionation: Int){
        fruitsStore.dwawings.move(fromOffsets: source, toOffset: destionation)
    }
}

struct E31FruitsListCell: View {
    var fruits: E31Fruits

    var body: some View{
        HStack{
            Image(fruits.imageName)
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width: 100, height: 75)
            Text(fruits.name)
        }
    }
}

struct E31FruitsDescriptionView: View {
    let selectedFruits: E31Fruits
    var body: some View {
        Form{
            Section(header: Text("ひと言")){
                Image(selectedFruits.imageName)
                    .resizable()
                    .presentationCornerRadius(13.5)
                    .aspectRatio(contentMode: .fit)
                    .padding()
                Text(selectedFruits.name)
                    .font(.headline)
                Text(selectedFruits.description)
                    .font(.largeTitle)
                HStack{
                    Text("在庫あり").font(.headline)
                    Spacer()
                    Image(systemName: selectedFruits.isBool ? "checkmark.circle" : "xmark.circle")
                }
            }
        }
    }
}

struct E31AddFruitsView: View {
    @State var fruitsStore: E31FruitsStore
    @State private var isBool = false
    @State private var fruitsName = ""
    @State private var description: String = ""
    @Binding var path: NavigationPath

    var body: some View {
        Form{
            Section(header: Text("詳細")){
                Image(systemName: "apple.logo")
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .padding()

                E31FruitsInputView(menu: "果物", fruitsInput: $fruitsName)
                E31FruitsInputView(menu: "ひと言", fruitsInput: $description)
                Toggle(isOn: $isBool){
                    Text("在庫")
                        .font(.headline)
                }
                .padding()
            }
            Button(action: addNewFruitsMenu){
                Text("品物追加")
            }
        }
    }

    func addNewFruitsMenu(){
        let newFruitsMenu = E31Fruits(
            id: UUID(),
            name: fruitsName,
            description: description,
            isBool: isBool,
            imageName: "りんごちゃん"
        )

        fruitsStore.dwawings.append(newFruitsMenu)
        path.removeLast()
    }
}

struct E31FruitsInputView: View {
    var menu: String
    @Binding var fruitsInput: String

    var body: some View {
        VStack(alignment: HorizontalAlignment.leading){
            Text(menu)
                .font(.title)
            TextField("\(menu)を入力してください。",text: $fruitsInput)
                .textFieldStyle(RoundedBorderTextFieldStyle())
        }
        .padding()
    }
}

#Preview {
    Essentials31ContentsView()
}

#Preview {
    E31FruitsDescriptionView(selectedFruits: E31FruitsStore().dwawings.first!)
}
/*不要なのでコメントアウト
 #Preview {
 E31AddFruitsView(fruitsStore: E31FruitsStore())
 }
 */

◾️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
    //じっくり48で追加
    case Ch30
    //じっくり49で追加
    case Ch31
}
//各項目に表示する文字列
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),
    //じっくり48で追加
    ListiOSApp17DevelopmentEssentials(id: 30, title: essentialsChapter30Title, view: .Ch30),
    //じっくり49で追加
    ListiOSApp17DevelopmentEssentials(id: 31, title: essentialsChapter31Title, view: .Ch31),
]

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)
            })
            //じっくり47で追加
        case .Ch29:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh29()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
            //じっくり48で追加
        case .Ch30:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh30()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
            //じっくり49で追加
        case .Ch31:
            return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh31()) {
                Text(dataiOSApp17DevelopmentEssentials.title)
            })
        }
    }
}

#Preview {
    iOSApp17DevelopmentEssentials()
}

以上。さてと続きはまた次回👀💦

ナビゲーションデスティネーションでまさか沼ってこの時間になるとは、、、💦
ま、解決してよかったよ〜〜〜〜〜〜

いいなと思ったら応援しよう!