SwiftUI NavigationSplitView 사용법

iPad나 Mac과 같은 넓은 화면에서 멀티컬럼 인터페이스를 구현할 때 NavigationSplitView는 정말 유용하다.

iOS 16부터 Swift에 도입된 이 뷰는 기존의 NavigationView를 대체하면서 더 강력한 기능을 제공한다.

SwiftUI에서 NavigationSplitView를 어떻게 효과적으로 사용할 수 있는지 살펴보자.

SwiftUI NavigationSplitView 사용법


기본 시그니처

NavigationSplitView의 기본 구조

NavigationSplitView는 최대 3개의 영역으로 구성된다:

  1. Sidebar – 주요 카테고리나 메뉴를 표시하는 영역
  2. Content – Sidebar에서 선택한 항목의 세부 콘텐츠를 보여주는 영역
  3. Detail – Content에서 선택한 항목의 상세 정보를 표시하는 영역

아이패드나 맥에서는 이 세 영역이 한 화면에 모두 표시될 수 있지만, 아이폰처럼 화면이 작은 기기에서는 하나의 영역만 표시되고 뒤로가기 버튼으로 이동하게 된다.

3개의 영역을 모두 사용한다면 Sidebar, Content, Detail 모두를 이용하지만, 2개의 컬럼으로 구성하고 싶을때는 SidebarDetail을 이용한다. 이 점을 알고 있으면 좋다. 사이드바와 콘텐트가 아닌 사이드바와 디테일이다.

기본적인 NavigationSplitView 구현

가장 기본적인 형태의 NavigationSplitView는 이렇게 구현할 수 있다:

Swift
struct ContentView: View {
    var body: some View {
        NavigationSplitView {
            // Sidebar 영역
            List {
                Text("메뉴 1")
                Text("메뉴 2")
            }
            .navigationTitle("메뉴")
        } content: {
            // Content 영역
            Text("콘텐츠 영역입니다")
                .navigationTitle("콘텐츠")
        } detail: {
            // Detail 영역
            Text("상세 정보 영역입니다")
                .navigationTitle("상세")
        }
    }
}

상태를 통한 뷰 전환 구현하기

실제 NavigationSplitView를 이용한 앱에서는 사용자가 선택한 항목에 따라 다른 뷰를 보여줘야 한다. 이를 위해 상태(State) 값을 사용할 수 있다.

Swift
struct ContentView: View {
    // 현재 선택된 콘텐츠 타입을 저장하는 상태 변수
    @State private var selectedContent: ContentViewType? = nil
    
    // 아이폰에서 현재 표시할 컬럼을 제어하는 상태 변수
    @State private var preferredColumn: NavigationSplitViewColumn = .sidebar
    
    var body: some View {
        NavigationSplitView(columnVisibility: .constant(.all), 
                           preferredCompactColumn: $preferredColumn) {
            // Sidebar 영역
            List(selection: $selectedContent) {
                Button("소비 내역") {
                    selectedContent = .spendingHistory
                    // 아이폰에서는 다음 컬럼으로 이동
                    preferredColumn = .content
                }
                
                Button("구매 목록") {
                    selectedContent = .shoppingList
                    preferredColumn = .content
                }
            }
            .navigationTitle("메뉴")
        } content: {
            // Content 영역 - 선택된 항목에 따라 다른 뷰 표시
            if let selectedContent {
                switch selectedContent {
                case .spendingHistory:
                    SpendingHistoryView()
                case .shoppingList:
                    ShoppingListView()
                }
            } else {
                Text("왼쪽에서 메뉴를 선택해주세요")
            }
        } detail: {
            // Detail 영역
            Text("상세 정보 영역입니다")
        }
    }
}

// 콘텐츠 뷰 타입을 정의하는 열거형
enum ContentViewType: String, Identifiable {
    case spendingHistory // 소비 내역 보기
    case shoppingList    // 구매 목록 보기
    // case dashboard    // 대시보드 보기 (필요시 추가)
    // case detail       // 세부 정보 보기 (필요시 추가)
    
    var id: String { self.rawValue }
}

아이폰에서의 특별한 처리

아이폰은 화면 크기 제약으로 인해 한 번에 하나의 컬럼만 표시할 수 있다. 그래서 preferredCompactColumn 속성을 사용해 현재 표시할 컬럼을 지정해줘야 한다.

Swift
@State private var preferredColumn: NavigationSplitViewColumn = .sidebar

NavigationSplitView(preferredCompactColumn: $preferredColumn) {
    // Sidebar 내용
} content: {
    // Content 내용
} detail: {
    // Detail 내용
}

버튼을 눌렀을 때 다음 컬럼으로 이동하도록 하려면:

Swift
Button("소비 내역 보기") {
    selectedContent = .spendingHistory
    // 아이폰에서 다음 화면으로 전환
    if UIDevice.current.userInterfaceIdiom == .phone {
        preferredColumn = .content
    }
}

NavigationLink를 활용한 뷰 전환

상태 변수 외에도 NavigationLink를 사용해 뷰를 전환할 수도 있다.

Swift
swiftList {
    NavigationLink(value: ContentViewType.spendingHistory) {
        Label("소비 내역", systemImage: "chart.bar")
    }
    NavigationLink(value: ContentViewType.shoppingList) {
        Label("구매 목록", systemImage: "cart")
    }
}
.navigationDestination(for: ContentViewType.self) { viewType in
    switch viewType {
    case .spendingHistory:
        SpendingHistoryView()
    case .shoppingList:
        ShoppingListView()
    }
}

컬럼 가시성 제어하기

NavigationSplitView의 컬럼 표시 여부를 프로그래밍 방식으로 제어할 수도 있다.

Swift
@State private var columnVisibility: NavigationSplitViewVisibility = .all

NavigationSplitView(columnVisibility: $columnVisibility) {
    // Sidebar 영역
} content: {
    // Content 영역
} detail: {
    // Detail 영역
}

// 버튼을 눌러 컬럼 가시성 변경
Button("사이드바만 보기") {
    columnVisibility = .doubleColumn
}

NavigationSplitViewVisibility는 NavigationSplitView에서 현재 어떤 컬럼들이 보여질지를 결정하는 열거형이.

  • .all: 모든 컬럼(Sidebar, Content, Detail)을 표시
  • .doubleColumn: Sidebar와 Content만 표시 (Detail 숨김)
  • .detailOnly: Detail 컬럼만 표시
  • .automatic: 시스템이 화면 크기에 따라 자동으로 결정

주로 사용자가 화면 레이아웃을 직접 조절할 수 있게 하고 싶을 때나 앱의 다양한 상태에 따라 적절한 레이아웃을 보여주고 싶을 때 사용하는 옵션이다.

NavigationSplitView 사용법을 마치며


SwiftUI의 NavigationSplitView는 다양한 화면 크기에 적응하는 멀티컬럼 인터페이스를 쉽게 구현할 수 있게 해준다.

상태 관리를 통해 다양한 뷰 전환 방식을 구현할 수 있고, 아이폰과 같은 작은 화면에서도 잘 동작하도록 만들 수 있다.

특히 iPad나 Mac 앱을 개발할 때 NavigationSplitView를 잘 활용하면 사용자 경험을 크게 향상시킬 수 있다.

NavigationSplitView에 대한 더 자세한 정보는 Apple 공식 문서에서 확인할 수 있다.