안녕하세요!
SwiftUI에서 항상 느꼇던 불편한점중 하나가 네비게이션이였는데요
이를 해결해주는게 나온지 좀 됐지만 이제 해보려합니다!
(진작에 나왔을 녀석이여야 했는데...)
iOS16 타겟을 쓸일이 없지만... 곧 쓸 지도 모르니까요! 😁
타입은 새롭지만 저희한텐 익숙합니다
push pop되는 그런 인터페이스를 나타내기때문이죠!
이것말고도 NavigationSplitView 타입도 있어요 mac이나 iPad에서 사용하는 다중열을 보여줄 때 사용하는 타입이죠
NavigationSplitView은 스킵하고 오늘은 NavigationStack을 알아보려합니다
이전에는 NavigationLink를 이용한 방식으로
var body: some View {
NavigationView {
NavigationLink {
뷰(color: .red, order: 1)
} label: {
Text("타이틀")
}
}
}
이렇게 타이틀과 뷰를 넣어주는 식으로 사용됬다면
새로운 버전으로는 뷰 대신에 값을 전달합니다.
var body: some View {
NavigationStack {
NavigationLink(value: Color.brown) {
뷰(color: .orange, order: 2)
}
.navigationDestination(for: Color.self) { color in
뷰(color: color, order: 3)
}
}
}
NavigationLink에 hashable한 value를 넣어주면
.navigationDestination 메서드로 값을 받아와서 값에따라 원하는 뷰를 그려줄 수 있어요
NavigationStack은 Stack이 표시하는 모든데이터를 나타내는 경로를 추적할 수 있어요
위의 예제는 생성자에서 path를 생략했지만 필요에 따라서 path를 바인딩 해줄 수 있어요
루트만 표시하는경우 path는 비어있고
스택내부 또는 스택에 푸시된 뷰 내부에서 선언된 모든 네비게이션 대상을 추적합니다
경로가 비었기때문에 위의 그림처럼 푸시된 뷰 목록도 비어있는 상태입니다.
Apple Pie 목록을 클릭해서 푸시된다면
path에 추가되고
스택은 경로값에 대상을 매핑하여 스택에서 푸시할 뷰를 결정합니다
뒤로가기 버튼을 누르면 스택이 경로 및 푸시된 뷰에서 마지막 항목을 제거합니다.
path를 사용한 네비게이션은 간단하게 배열에 값을 추가하고 제거하는 과정을 통해 라우팅을 컨트롤 할 수 있어요
struct TestNavigationStack: View {
@State private var path: [Color] = []
var body: some View {
NavigationStack(path: $path) {
VStack {
Button {
path.append(.yellow)
} label: {
Text("나랑노랑")
}
}
.navigationDestination(for: Color.self) { color in
뷰(color: color, order: 3)
.overlay {
VStack {
Button {
path.append([Color.red,Color.orange,Color.blue,Color.gray,Color.indigo].randomElement()!)
} label: {
Text("랜덤푸시")
}
Button {
path.removeAll()
} label: {
Text("초기화")
}
}
}
}
}
}
}
이를 이용해서 이젠 SwiftUI에서도 코디네이터 방식도 손쉽게 해볼 수 있을 것 같다고 생각들었어요
간단하게 프로토타입만 작성해봤는데 동작은 잘 하더라구요
@main
struct test_swiftUIApp: App {
@StateObject var coordinator: Coordinator = Coordinator()
var body: some Scene {
WindowGroup {
NavigationStack(path: $coordinator.route) {
TestNavigationStack()
.environmentObject(coordinator)
.navigationDestination(for: Color.self) { color in
뷰(color: color, order: 3)
.overlay {
VStack {
Button {
coordinator.push([Color.red,Color.orange,Color.blue,Color.gray,Color.indigo].randomElement()!)
} label: {
Text("랜덤푸시")
}
Button {
coordinator.popToRoot()
} label: {
Text("초기화")
}
}
}
}
}
}
}
}
struct TestNavigationStack: View {
@EnvironmentObject var coordinator: Coordinator
var body: some View {
VStack {
Button {
coordinator.push(.yellow)
} label: {
Text("나랑노랑")
}
}
}
}
final class Coordinator: ObservableObject {
@Published var route: [Color] = []
func push(_ color: Color) {
route.append(color)
}
func pop() {
route.removeLast()
}
func popToRoot() {
route.removeAll()
}
}
NavigationStack을 사용할 때 주의할 점으로
NavigationStack 안쪽에 navigationDestination가 존재해야해요
인식하지 못하기 때문에 바깥에 쓴것과 navigationDestination를 정의하지 않는 것과 동일하죠
두 경우 모두 경고표시의 뷰를 볼 수 있습니다.
참조
'iyOmSd > Title: SwiftUI' 카테고리의 다른 글
[SwiftUI] Charts 실전편 (feat. iOS16+ apple framework) (0) | 2023.07.29 |
---|---|
[SwiftUI] Charts 이론편 (feat. iOS16+ apple framework) (0) | 2023.06.29 |
[SwiftUI] 분리된 프레임워크(모듈) 리소스(Font, Color, Image)접근 (0) | 2023.02.24 |
[SwiftUI] Widget LiveActivity (feat. Dynamic Island) 잠금화면 기능 (2) | 2023.01.14 |
[SwiftUI] @FocusState (0) | 2022.10.27 |