[SwiftUI] NavigationStack

2023. 9. 2. 01:59·Swift/정리
728x90

기존 네비게이션

NavigationLink("Details", isActive: $item.showDetail) { DetailView() }

새로운 네비게이션 API

  • Navigation의 새로운 종류
    • NavigationStack
      • 새로운 시스템 설정 앱, 애플워치 앱 등 (푸시 팝 인터페이스)
    NavigationStack(path: $path) {
    	NavigationLink("Details", value: value)
    }
    
    • NavigationSplitView
      • Mail 또는 Notes와 같은 다중열 애플리케이션에 적합
      • iPhone, iPad의 SlideOver, AppleWatch와 Apple TV의 단일 열 스택에 자동으로 적응

NavigationSplitView {
	RecipeCategories()
} detail: {
	RecipeGrid()
 } 

Recipes for navigation

  • NavigationStack
    • path에 경로를 지정해주고 마음대로 경로를 설정해 줄 수 있다.

@State private var path: [Recipe] = [] 

NavigationStack(path: $path {
	List(Category.allCases) { category in
		Section(category.localizedName) {
			ForEach(dataModel.recipes(in: category)) { recipe in
				NavigationLink(recipe.name, value: recipe)
				}
			}
		}
	.navigationTitle("Categories")
	.navigationDestination(for: Recipe.self) { recipe in 
		RecipeDetail(recipe: recipe)
		}
	}
}
  • NavigationSplitView
    • iPad와 iPhone에서 자동으로 화면을 분활해서 보여준다.

struct MultipleColumns: View {
    @State private var selectedCategory: Category?
    @State private var selectedRecipe: Recipe?
    @StateObject private var dataModel = DataModel()

    var body: some View {
        NavigationSplitView {
            List(Category.allCases, selection: $selectedCategory) { category in
                NavigationLink(category.localizedName, value: category)
            }
            .navigationTitle("Categories")
        } content: {
            List(
                dataModel.recipes(in: selectedCategory),
                selection: $selectedRecipe)
            { recipe in
                NavigationLink(recipe.name, value: recipe)
            }
            .navigationTitle(selectedCategory?.localizedName ?? "Recipes")
        } detail: {
            RecipeDetail(recipe: selectedRecipe)
        }
    }
}

struct RecipeDetail: View {
    var recipe: Recipe?

    var body: some View {
        Text("Recipe details go here")
            .navigationTitle(recipe?.name ?? "")
    }
}

class DataModel: ObservableObject {
    @Published var recipes: [Recipe] = builtInRecipes

    func recipes(in category: Category?) -> [Recipe] {
        recipes
            .filter { $0.category == category }
            .sorted { $0.name < $1.name }
    }
}

Persistent state

  • 네비게이션 상태를 유지하는데 필수 요소
    • Codable
    • SceneStorage
    1. 네비게이션 상태를 NavigationModel 유형으로 요약
    2. 네비게이션 모델을 Codable로 만듬
    3. 마지막으로 SceneStorage를 사용하여 모델을 저장하고 복원
class NavigationModel: ObservableObject, Codable {
    @Published var selectedCategory: Category?
    @Published var recipePath: [Recipe] = []

    enum CodingKeys: String, CodingKey {
        case selectedCategory
        case recipePathIds
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encodeIfPresent(selectedCategory, forKey: .selectedCategory)
        try container.encode(recipePath.map(\\.id), forKey: .recipePathIds)
    }

    init() {}

    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.selectedCategory = try container.decodeIfPresent(
            Category.self, forKey: .selectedCategory)

        let recipePathIds = try container.decode([Recipe.ID].self, forKey: .recipePathIds)
        self.recipePath = recipePathIds.compactMap { DataModel.shared[$0] }
    }

    var jsonData: Data? {
        get {
            try? JSONEncoder().encode(self)
        }
        set {
            guard let data = newValue,
                  let model = try? JSONDecoder().decode(NavigationModel.self, from: data)
            else { return }
            self.selectedCategory = model.selectedCategory
            self.recipePath = model.recipePath

        }
    }

    var objectWillChangeSequence:
        AsyncPublisher<Publishers.Buffer<ObservableObjectPublisher>>
    {
        objectWillChange
            .buffer(size: 1, prefetch: .byRequest, whenFull: .dropOldest)
            .values
    }
}
728x90

'Swift > 정리' 카테고리의 다른 글

[SwiftUI] Combine  (0) 2023.09.16
[Swift] SwiftLint  (0) 2023.09.04
[Swift] 기본 문법 정리  (0) 2023.03.19
[Swift] 첫 iOS 앱 개발자를 위한 가이드 from Lingo  (0) 2023.03.13
[Swift] Swift에서 사용되는 디자인 패턴(pattern)과 예제 코드  (0) 2023.03.04
'Swift/정리' 카테고리의 다른 글
  • [SwiftUI] Combine
  • [Swift] SwiftLint
  • [Swift] 기본 문법 정리
  • [Swift] 첫 iOS 앱 개발자를 위한 가이드 from Lingo
bulmang
bulmang
모바일 개발자 도전
  • bulmang
    bulmang
    bulmang
  • 전체
    오늘
    어제
    • 분류 전체보기 (208)
      • 알고리즘 (68)
        • List (3)
        • Two Pointer (6)
        • Binary Search (4)
        • Prefix Sum (3)
        • Sort (4)
        • Brute Force (5)
        • Array (2)
        • String (4)
        • 프로그래머스 (12)
        • 백준 (9)
        • Queue (2)
        • Stack (2)
        • Recursion (12)
      • Computer Science (16)
        • Computer Architecture (6)
        • Operating System (5)
        • Network (2)
        • 기타 (2)
        • System Programming (1)
      • Swift (70)
        • 개발 (24)
        • 정리 (25)
        • 문법 (20)
      • Flutter (24)
      • 기타 (12)
        • 후기 (12)
      • Git (6)
      • Ios 오픈소스 (5)
      • UI 디자인 (5)
      • AppleScript (2)
  • 링크

    • Notion
    • Github
  • 태그

    재귀
    Java
    피플
    IOS
    컴퓨터구조
    til
    문법
    백준
    협업
    riverpod
    코딩테스트
    자료구조
    FLUTTER
    알고리즘
    Apple Developer Academy
    today i learned
    개발
    Xcode
    SwiftUI
    Swift
  • 최근 댓글

  • 최근 글

  • 인기 글

  • 250x250
  • hELLO· Designed By정상우.v4.10.2
bulmang
[SwiftUI] NavigationStack
상단으로

티스토리툴바