SwiftUI 튜토리얼 1 - App Principles

mmmYoung·2022년 7월 14일
0

SwiftUI

목록 보기
1/3

https://developer.apple.com/tutorials/swiftui-concepts
공식 문서를 정리한 글입니다.

App Principles

Swift UI App 살펴보기

소개 및 앱의 구조

우선 Swift UI는 사용자 인터페이스를 쉽게 구성할 수 있도록 도와주는 선언형 프레임워크입니다. 앱의 구조는 App, Scene,View 프로토콜로 이루어져있습니다.
우선 App 파일을 살펴보면 다음과 같습니다.

import SwiftUI

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

@main 속성을 적용하며 앱의 진입점을 알립니다. 이 속성은 반드시 하나만 있어야 해요.

앱 프로토콜 내부에는 body가 존재하고, 여기서는 Scene인 앱의 컨텐츠를 리턴합니다. Scene에는 사용자 인터페이스를 정의하는 뷰 계층을 포함하고 있어요. 여기서는 WindowGroup을 사용했지만 이외에도 Window, DocumentGroup,Settings가 존재합니다.

ContentView는 이미지나 텍스트로 구성된 뷰의 계층을 만드는 커스텀 뷰 입니다. 이것에 대해 더 자세히 알아봅시다!

ContentView


SwiftUI에서, 씬은 앱의 UI인 뷰 계층을 포함하고 있습니다.
뷰 계층은 뷰와 연결된 다른 뷰들의 레이아웃을 정의합니다.
예를 들어 아래 코드를 보면, WindowGroup scene은 ContentView를 포함하고, ContentView는 다른 뷰들을 포함하고 있습니다.

import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundColor(.accentColor)
            Text("Hello, world!")
        }
        .padding()
    }
}

ContentView는 View 프로토콜을 따르는 구조입니다. 그리고 위의 MyApp과 마찬가지로 body속성을 갖게 됩니다.

VStack은 Row와 같은 역할을 입니다. VStack은 내부에 포함된 모든 뷰들을 동시에 렌더링하기 때문에, 서브 뷰가 적을 때 사용하는게 좋습니다.서브 뷰가 많아질 경우, 화면에 표시된 뷰만 렌더링하는 LazyVStack을 사용하는 것을 추천합니다.

VStack의 첫번째 서브 뷰는 이미지입니다. init(systemName:) 메소드를 이용하여 기본 이미지를 불러왔습니다. 기본 아이콘은 SF Symbols 라이브러리에 있습니다. view modifier인 imageScale(:)과 foregroundColor(:)를 이용해 이미지의 크기와 색상을 지정했습니다.

두번째 서브 뷰는 읽기 전용 텍스트입니다. 이미지와 마찬가지로 modifier를 통해 디테일을 수정할 수 있습니다.

이후 패딩을 이용하여 여백을 줍니다. 뷰 내부에 여백을 어디에 얼만큼 줄 지 정할 수 있습니다. 예를 들어 padding([.bottom, .trailing], 20)인 경우, 아래와 오른쪽에 20만큼의 여백이 생기게 됩니다.

Scene을 이용하여 뷰 계층 정하기

SwiftUI는 앱의 ui를 만드는 데 도움이 되는 빌딩 블록을 제공합니다. 이중 하나는 뷰 계층이 포함된 Scene입니다. SwiftUI가 제공하는 씬에서 앱의 뷰 계층을 지정하거나 커스텀 씬을 생성할 수 있습니다. 두 가지 방법 모두 알아봅시다.

앱에 씬 추가하기

import SwiftUI

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            TabView {
                ContentView()
                    .tabItem {
                        Label("Journal", systemImage: "book")
                    }
                SettingsView()
                    .tabItem {
                        Label("Settings", systemImage: "gear")
                    }
            }
        }
    }
}
  • WindowGroup 씬은 가장 일반적으로 사용됩니다. macOS 및 iPadOS의 상태를 구분하여 동작을 제공합니다.

이제 구조는 익숙해졌으니, 구조 설명은 생략합니다. 뷰 계층에서 루트 노드는 TabView입니다. TabView는 여러 탭을 통해 서브 뷰들을 스위칭할 수 있습니다.

루트 노드 안의 서브 뷰는 ContentView와 SettingsView가 됩니다. 둘다 커스텀 뷰! 각각의 뷰에는 tabItem(_:) modifier를 통해 탭의 이미지나 텍스트를 만들어줍니다.

다른 뷰 계층 정의하기

아이폰이랑 맥에서도 앱을 동작하고 싶어요! 하지만 위의 코드를 보면 맥 os에는 맞지 않아보입니다. 맥에 맞게 다른 뷰 계층을 선언하는 코드를 추가해봅시다.

import SwiftUI

@main
struct MyApp: App {
    var body: some Scene {
        #if os(iOS)
        WindowGroup {
            TabView {
                ContentView()
                    .tabItem {
                        Label("Journal", systemImage: "book")
                    }
                
                SettingsView()
                    .tabItem {
                        Label("Settings", systemImage: "gear")
                    }
            }
        }
        #elseif os(macOS)
        WindowGroup {
            AlternativeContentView()
        }
        
        Settings {
            SettingsView()
        }
        #endif
    }
}

이전 코드와 달라진 점은 조건문을 통해 iOS와 macOS를 구분한 뒤, macOS의 경우 WindowGroup에 또다른 뷰 계층을 정의해주었습니다.
앞에서 본 뷰 계층과는 다르게, 여기서는 루트 노드가 커스텀 뷰인 AlternativeContentView가 되었습니다.

두번째 씬인 Settings(macOS에만 존재해요!) 에서는 Mac의 앱 메뉴에서 사용할 수 있는 설정 메뉴 항목을 제공합니다.

The Settings 씬은 커스텀 뷰인 SettingView를 포함하고 있어요. 여기서는 아래와 같은 앱 설정창을 보여줍니다.

  • 이렇게 뷰 계층을 두 개로 나누어 정의하면, 반드시 타겟 플랫폼에 따라 사용할 계층이 무엇인지 지정해야 합니다.

커스텀 씬 만들기

지금까지는 MyApp 구조에서 다양한 버전의 앱을 정의하는 작업을 해보았습니다. 그렇지만 코드가 너무 길어 유지관리하기 어려워지겠죠?ㅠ
이를 해결하기 위해서는 커스텀 씬을 사용해봅시다. 커스텀 씬은 다른 씬으로부터 구성할 수 있습니다.

import SwiftUI

struct MyScene: Scene {
    var body: some Scene {
        WindowGroup {
            TabView {
                ContentView()
                    .tabItem {
                        Label("Journal", systemImage: "book")
                    }
                
                SettingsView()
                    .tabItem {
                        Label("Settings", systemImage: "gear")
                    }
            }
        }
    }
}

iOS 기기에서 보여줄 씬을 분리하여, 커스텀 씬인 MyScene을 만들어 보았습니다. 역시 Scene 프로토콜을 따르는 구조입니다.

App 프로토콜을 따르는 구조와 마찬가지로, body가 필요해요!
내부의 WindowGroup부터는 위에서 먼저 다룬 "앱에 씬 추가하기"에서 했던 코드와 일치합니다.

import SwiftUI

struct MyAlternativeScene: Scene {
    var body: some Scene {
        WindowGroup {
            AlternativeContentView()
        }
        
        #if os(macOS)
        Settings {
            SettingsView()
        }
        #endif
    }
}

macOS를 위한 씬도 같은 방법으로 만들어 주었습니다.

body 속성은 두번째 씬인 Settings를 포함하는데요, 이 씬은 macOS에서만 가능하니 if 조건문을 통해 지정된 플랫폼인지 확인하는 작업을 거쳤습니다.

코드 리팩토링

MyScene과 MyAlternativeScene를 만들어 보았습니다. "다른 뷰 계층 정의하기"에서 배운 MyApp 구조에서 커스텀씬을 이용한 구조로 코드 리팩토링을 해봅시다!

import SwiftUI

@main
struct MyApp: App {
    var body: some Scene {
        #if os(iOS)
        MyScene()
        #elseif os(macOS)
        MyAlternativeScene()
        #endif
    }
}

MyApp 구조가 훨씬 더 간결하게 바뀌었네요!
짝짝짝~ 유지관리가 조금 더 쉬워졌습니다.

profile
안냐세여

0개의 댓글