【じっくり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()
}
てな感じではめ込んでみても、
で、どーやら画像をアセットに嵌め込む必要がそろそろありそうだし、そろそろやってもいいかなあって感じなので、
@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()
}
}
てな感じで〜〜〜
とりあえず今回も以上かな笑🧐
今回のコードまとめ
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()
}
以上。さてと続きはまた次回👀💦
ナビゲーションデスティネーションでまさか沼ってこの時間になるとは、、、💦
ま、解決してよかったよ〜〜〜〜〜〜