본문 바로가기
iOS 프로그래밍

SwiftUI로 커스텀 뷰 생성하기: 나만의 UI 컴포넌트 만들기

by iOS 2025. 4. 30.

SwiftUI 커스텀 뷰 생성하기: 나만의 UI 컴포넌트를 만들어 코드를 재사용하고 앱을 모듈화하세요. View 구조체 정의부터 데이터 전달까지 단계별로 설명합니다.

 

SwiftUI에서 UI는 View라는 기본적인 구성 요소를 조합하여 만들어집니다. Text, Image, Button, VStack 등은 SwiftUI가 기본으로 제공하는 뷰들입니다. 하지만 실제 앱을 개발하다 보면 특정 디자인 패턴이나 기능의 조합이 여러 화면에서 반복되거나, 특정 UI를 독립적으로 관리하고 싶을 때가 많습니다. 이때 필요한 것이 바로 커스텀 뷰(Custom View)를 만드는 것입니다.

 

커스텀 뷰는 개발자가 직접 정의하는 재사용 가능한 UI 컴포넌트입니다. 복잡한 UI를 작고 관리하기 쉬운 단위로 분할하고, 한 번 작성한 코드를 여러 곳에서 재사용함으로써 개발 효율성과 코드의 가독성, 유지보수성을 크게 높일 수 있습니다. 이번 글에서는 SwiftUI에서 커스텀 뷰를 생성하고 사용하는 기본적인 방법을 배워보겠습니다.

 

커스텀 뷰란 무엇인가?

SwiftUI에서 커스텀 뷰는 기본적으로 View 프로토콜을 따르는 구조체(struct)입니다. 이 구조체는 var body: some View라는 속성을 가지고 있으며, 이 body 내부에 커스텀 뷰가 화면에 그릴 내용을 다른 뷰들의 조합으로 선언합니다.

예를 들어, 사용자 프로필을 보여주는 카드 UI가 앱의 여러 곳에서 사용된다면, 이 카드 UI 전체를 하나의 ProfileCardView라는 커스텀 뷰로 만들 수 있습니다. 이렇게 함으로써 프로필 카드를 보여줘야 할 때마다 ProfileCardView()만 호출하면 되고, 카드 디자인을 변경하고 싶다면 ProfileCardView 구조체의 코드만 수정하면 됩니다.

 

간단한 커스텀 뷰 만들기

Xcode에서 새로운 SwiftUI 뷰 파일을 생성하는 것부터 시작하겠습니다.

  1. 새 파일 생성: Xcode 네비게이터 영역에서 프로젝트 폴더를 선택하고, 메뉴 바에서 File > New > File...을 선택합니다.
  2. 템플릿 선택: iOS 탭 아래 User Interface 섹션에서 SwiftUI View 템플릿을 선택한 후 Next 버튼을 클릭합니다.
  3. 파일 이름 지정: 파일 이름을 입력합니다 (예: GreetingView). 저장될 위치를 확인하고 Create 버튼을 클릭합니다.

새로운 Swift 파일(GreetingView.swift)이 생성되고 다음과 같은 기본 코드가 나타날 것입니다.

import SwiftUI

struct GreetingView: View { // View 프로토콜을 따르는 구조체
    var body: some View { // 뷰의 내용을 정의하는 body 속성
        Text("Hello, World!") // 기본으로 포함된 Text 뷰
    }
}

#Preview { // 미리보기 캔버스에서 보여줄 내용
    GreetingView() // GreetingView 인스턴스 미리보기
}

이제 body 내부에 이 커스텀 뷰가 실제로 화면에 표시할 내용을 원하는 대로 작성하면 됩니다. 예를 들어 VStack을 사용하여 이미지와 텍스트를 조합해 보겠습니다.

import SwiftUI

struct GreetingView: View {
    var body: some View {
        VStack { // 세로 스택으로 이미지와 텍스트 배치
            Image(systemName: "star.fill") // 별 시스템 이미지
                .foregroundColor(.yellow)
                .imageScale(.large)

            Text("안녕하세요!") // 환영 메시지 텍스트
                .font(.headline)
        }
        .padding() // 스택 전체에 패딩 적용
        .background(Color.blue.opacity(0.3)) // 배경색 적용
        .cornerRadius(10) // 모서리 둥글게
    }
}

#Preview {
    GreetingView()
}

Xcode의 미리보기 캔버스(Resume 버튼 필요시 클릭)에서 방금 만든 GreetingView의 결과물을 확인할 수 있습니다.

 

커스텀 뷰 재사용하기

이렇게 만든 GreetingView는 이제 SwiftUI의 빌트인 뷰들처럼 다른 뷰의 body 내에서 여러 번 재사용할 수 있습니다. 예를 들어 ContentView에서 GreetingView를 두 번 사용해 보겠습니다.

ContentView.swift 파일로 돌아가서 ContentView 구조체의 body 내용을 다음과 같이 수정합니다.

import SwiftUI

struct ContentView: View {
    var body: some View {
        // 세로 스택 안에 GreetingView 인스턴스 두 개 배치
        VStack(spacing: 20) { // 스택 간격 20 지정
            GreetingView() // GreetingView 인스턴스 1
            GreetingView() // GreetingView 인스턴스 2
        }
    }
}

#Preview {
    ContentView()
}

미리보기 캔버스를 보면 GreetingView가 두 번 반복되어 표시되는 것을 확인할 수 있습니다. 코드를 한 번만 작성하고 필요한 곳에서 여러 번 사용할 수 있게 된 것입니다.

 

뷰에 데이터 전달하기: 속성 (Properties) 사용

대부분의 경우 커스텀 뷰는 고정된 내용이 아니라 동적인 데이터를 표시해야 합니다. 예를 들어 위의 GreetingView에서 "안녕하세요!" 대신 특정 사용자의 이름을 포함하여 "안녕하세요, [이름]!"이라고 표시하고 싶을 수 있습니다. 이럴 때 커스텀 뷰의 구조체에 속성(Properties)을 추가하여 외부로부터 데이터를 전달받습니다.

GreetingView.swift 파일에서 GreetingView 구조체에 name 속성을 추가하고 Text 뷰에서 이 속성을 사용하도록 수정합니다.

import SwiftUI

struct GreetingView: View {
    // 외부에서 전달받을 name 속성 (상수 let으로 선언)
    let name: String

    var body: some View {
        VStack {
            Image(systemName: "star.fill")
                .foregroundColor(.yellow)
                .imageScale(.large)

            // 전달받은 name 속성 값을 사용하여 텍스트 표시
            Text("안녕하세요, \(name)님!")
                .font(.headline)
        }
        .padding()
        .background(Color.blue.opacity(0.3))
        .cornerRadius(10)
    }
}

// 미리보기에서도 name 값을 전달해야 합니다.
#Preview {
    // name 속성에 값을 전달하여 GreetingView 인스턴스 생성
    GreetingView(name: "미리보기 사용자")
}

구조체에 name이라는 저장 속성을 추가했으므로, 이제 GreetingView의 인스턴스를 생성할 때는 반드시 name에 해당하는 값을 전달해야 합니다 (구조체의 자동 멤버와이즈 초기화 구문 덕분입니다).

이제 ContentView에서 GreetingView를 사용할 때 서로 다른 이름을 전달해 보겠습니다.

import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack(spacing: 20) {
            // 각 GreetingView 인스턴스에 다른 name 값 전달
            GreetingView(name: "김철수") // 이름 전달
            GreetingView(name: "이영희") // 다른 이름 전달
            GreetingView(name: "박민수") // 또 다른 이름 전달
        }
    }
}

#Preview {
    ContentView()
}

미리보기 캔버스를 보면 각 GreetingView 인스턴스가 전달받은 이름에 따라 다른 텍스트를 표시하는 것을 확인할 수 있습니다. 이처럼 속성을 사용하면 같은 커스텀 뷰 구조체를 가지고 다양한 데이터를 표시할 수 있습니다.

 

뷰 수정자 적용하기

커스텀 뷰의 body 내부에 있는 빌트인 뷰들에는 평소처럼 뷰 수정자를 적용할 수 있습니다. 또한, 커스텀 뷰 자체에도 뷰 수정자를 적용할 수 있으며, 이때 수정자는 커스텀 뷰의 body 전체에 정의된 내용에 영향을 미칩니다.

import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack(spacing: 20) {
            GreetingView(name: "김철수")
                .border(Color.red) // 첫 번째 GreetingView 인스턴스에 테두리 적용

            GreetingView(name: "이영희")
                .opacity(0.7) // 두 번째 GreetingView 인스턴스의 투명도 변경

            GreetingView(name: "박민수")
        }
        .padding() // VStack 전체에 패딩 적용
    }
}

#Preview {
    ContentView()
}

GreetingView() 인스턴스 뒤에 체이닝하여 적용한 .border().opacity() 수정자는 해당 인스턴스에만 영향을 미칩니다.

복잡한 뷰 조합하기

실제 앱의 UI는 이러한 커스텀 뷰들을 VStack, HStack, ZStack과 같은 레이아웃 컨테이너 안에 중첩시키거나, 다른 커스텀 뷰 안에 또 다른 커스텀 뷰를 포함시키는 방식으로 구성됩니다. 작고 명확한 목적을 가진 커스텀 뷰들을 조립하여 최종 화면을 만드는 것이 SwiftUI 개발의 핵심 패턴입니다.

왜 커스텀 뷰를 만들어야 하는가?

커스텀 뷰를 만드는 것은 다음과 같은 분명한 이점을 제공합니다.

  • 재사용성: 동일한 UI 패턴을 한 번만 작성하고 앱의 여러 곳에서 반복하여 사용할 수 있습니다.
  • 모듈성: 복잡한 UI를 작고 독립적인 논리적 단위로 분할하여 코드 관리가 용이해집니다. 각 커스텀 뷰는 자체적인 역할과 데이터를 가집니다.
  • 가독성: 복잡한 코드가 커스텀 뷰라는 의미 있는 이름으로 추상화되어 코드를 읽기 쉬워집니다.
  • 유지보수성: 특정 UI 디자인이나 기능에 변경이 필요할 때, 해당 커스텀 뷰의 코드만 수정하면 이를 사용하는 모든 곳에 변경 사항이 반영됩니다.

 

마무리

SwiftUI에서 커스텀 뷰를 만드는 것은 View 프로토콜을 따르는 구조체를 정의하고, body 내부에 UI 내용을 선언하며, 외부로부터 데이터를 전달받기 위해 속성을 추가하는 간단한 과정입니다. 이렇게 만들어진 커스텀 뷰를 조합하여 복잡한 화면을 효율적으로 구축하는 것이 SwiftUI 개발의 기본입니다.

 

커스텀 뷰는 코드의 재사용성, 모듈성, 가독성, 유지보수성을 크게 향상시키므로, 앞으로 SwiftUI 앱을 개발할 때 UI의 특정 부분을 커스텀 뷰로 분리하는 습관을 들이는 것이 중요합니다. 다양한 형태의 커스텀 뷰를 직접 만들어보고, 필요한 데이터를 속성으로 전달하며 뷰를 재사용하는 연습을 꾸준히 하시길 바랍니다.