[iOS] NavigationSplitView
NavigationSplitView
https://developer.apple.com/documentation/swiftui/navigationsplitview
✅ 목차
NavigationSplitView Overview
UI 예시
init - NavigationSplitViewVisibility
init - NavigationSplitViewColumn
Customize - navigationSplitViewStyle
Sample Code
⚙️ 개발환경
XCode 15.0 beta 2
단, preferredCompactColunm을 사용하지 않는다면 16.0으로도 가능.
NavigationSplitView Overview
NavigationSplitView는 2개 혹은 3개의 칼럼으로 화면을 표시하여, 사용자 경험을 향상.
NavigationSplitView의 기본 구조
NavigationSplitView(columnVisibility: $visibility,
preferredCompactColumn: $columns) {
// 사이드 바 영역
} content: {
// 컨텐트 영역
} detail: {
// 디테일 영역
}
NavigationSplitView의 경우 반드시 init(sidebar:, detail:)이 존재해야함.
UI 예시
아이패드 - 가로
아이패드 - 세로
아이폰
맥북
VisionOS의 경우에는 동일.
init - NavigationSplitViewVisibility
@available(iOS 16.0, macOS 13.0, tvOS 16.0, watchOS 9.0, *)
들어가기 전, 용어정리.
leading과 trailing은 우리가 레이아웃 잡을 때 자주 보았을 것임.
우리나라 기준으로는 leading은 왼쪽, trailing은 오른쪽임.
그러나, 어떤 국가의 경우에는 오른쪽에서 왼쪽으로 읽으므로, leading이 오른쪽 trailing이 왼쪽이 된다.
- detailOnly: 다 숨기고 오직 가장 trailiing에 위치한 것만 보여줌 (우리나라 기준 오른쪽)
- 그러니까 결국 디테일 부분의 뷰만 보임
- doubleColums: 가장 왼쪽 칼럼 숨김
- 그러니까 결국 사이드바만 숨김
- all: 다 보여줌
- 다 보여줌
- automatic: 현재 컨텍스트에 맞게 알아서 해줌
Note> 몇몇 플랫폼에서는 해당 옵션이 적용되지 않는데, macOS서는 컨텐트 영역 항상 보여줌.
init - NavigationSplitViewColumn
@available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *)
자 생각해보자.
아이폰이나 애플 워치의 경우에는 세개의 스택이 아니라 두개의 스택으로 표현된다.
그렇다면 NavigationSplitView에서 위에 있는 사이드바 > 컨텐트 > 디테일로 위치하기에 그 2개의 스택은 언제나
사이드바와 컨텐트였다.
그러나 사이드바와 디테일을 사용하고 싶은 경우에는?
해당 옵션을 주어서 사이드바 > 디테일 이렇게 조정이 가능하다.
Customize - navigationSplitViewStyle
Sample Code
//
// ContentView.swift
// NavigationSplitView
//
// Created by Hamlit Jason on 2023/08/05.
//
import SwiftUI
struct ContentView: View {
var 카페리스트: [Cafe] = [
Cafe.스타벅스,
Cafe.엔바이콘,
Cafe.공차,
Cafe.이디야
]
@State private var selection = Set<Cafe.ID>()
@State private var visibility: NavigationSplitViewVisibility = .all
@State private var columns: NavigationSplitViewColumn = .detail
var body: some View {
NavigationSplitView(columnVisibility: $visibility,
preferredCompactColumn: $columns) {
List(카페리스트, selection: $selection) { cafe in
Text(cafe.name)
}
} content: {
if let selectedCafe = 카페리스트.first(where: { $0.id == selection.first }) {
Text("컨텐트 영역 - \(selectedCafe.name)")
} else {
Text("컨텐트 영역 - 카페를 선택해주세요.")
}
} detail: {
if let selectedCafe = 카페리스트.first(where: { $0.id == selection.first }) {
Text("디테일 영역 - \(selectedCafe.name)")
} else {
Text("디테일 영역 - 카페를 선택해주세요.")
}
}
.navigationSplitViewStyle(.automatic)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct Cafe: Identifiable, Hashable {
var id: String { self.name }
var name: String
}
extension Cafe {
static let 스타벅스 = Cafe.init(name: "스타벅스")
static let 엔바이콘 = Cafe.init(name: "엔바이콘")
static let 이디야 = Cafe.init(name: "이디야")
static let 공차 = Cafe.init(name: "공차")
}