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의 단일 열 스택에 자동으로 적응
- NavigationStack
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
- 네비게이션 상태를 NavigationModel 유형으로 요약
- 네비게이션 모델을 Codable로 만듬
- 마지막으로 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
'SwiftUI > 정리' 카테고리의 다른 글
[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 |