iOS/SwiftUI

커스텀 뷰를 만들 때 고민점

Hamp 2025. 7. 5. 16:42
반응형

👋 들어가기 전

25

회사 일이 조금 소강 상태에 들어, 사이드 프로젝트를 본격적으로 시작하려고한다.

 

우리는 SwiftUI를 사용하기로 결정했고, 혼자 SwiftUI를 사용하여, 커스텀 뷰를 만들때

고민한 점을 시작으로, 이번 사이드 프로젝트의 여정을 기록하려고한다.


🏁 학습할 내용

  • 커스텀 뷰를 만들 때
  • ~View
  • ViewModifier
  • View Style
  • 비교

❓커스텀 뷰를 만들 때

 

SwiftUI를 통해 커스텀 뷰를 만드는 방법은 정말 많은 것 같다.

 

여기서 뷰를 만드는 의미는 실제 어떤 ~View 만드는 것이 아닌 UI적인 커스텀을 의미한다.

 

나는 대표적으로 3가지 방법을 알고있다.

  • ~View 정의
  • ViewModifier 정의
  • View Style 정의

각 내용을 먼저 알아보고 마지막에 비교를 해보자.


🏭 ~View 정의

📌 개요

SwiftUI에서 가장 기본적인 커스텀 방식

View 프로토콜을 따라는 struct를 정의해서 새로운 뷰를 만든다.

struct MyButton: View {
    let title: String
    let action: () -> Void

    var body: some View {
        Button(action: action) {
            Text(title)
                .font(.headline)
                .padding()
                .frame(maxWidth: .infinity)
                .background(Color.blue)
                .foregroundColor(.white)
                .cornerRadius(12)
        }
    }
}

✅ 장점

  • 재사용성과 조합성이 뛰어남내부에
  • @Binding, @State, @Environment 등 사용 가능 → 상태 기반 UI 구현 가능
  • 뷰 계층을 명확하게 분리할 수 있어 대규모 UI 구성에 유리

❌ 단점

  • 뷰 계층이 깊어질 경우 오히려 코드가 분산되어 추적이 어려울 수 있음
  • 단순한 스타일 변경에는 오버엔지니어링일 수 있음

🧑‍💻 사용 예시

  • 상태를 가진 독립적인 UI 컴포넌트 (예: 카드 뷰, 커스텀 버튼, 셀 등)
  • 뷰 계층을 분리하고자 할 때
  • View 타입 전체를 추상화하고자 할 때

✍️ ViewModifier

반복적으로 적용하는 스타일이나 효과를 커스텀 modifier로 추출할 때 사용.

구현 후, View protocol의 extension의 함수 형태로 만들면, 조금 더 쉽게 사용할 수 있다.

import SwiftUI

struct EmphasizedTextModifier: ViewModifier {
    func body(content: Content) -> some View {
        content
            .font(.system(size: 20, weight: .bold))
            .foregroundColor(.orange)
            .padding(8)
            .background(Color.orange.opacity(0.1))
            .cornerRadius(8)
    }
}

// Modifier를 더 자연스럽게 쓰기 위한 확장
extension View {
    func emphasized() -> some View {
        self.modifier(EmphasizedTextModifier())
    }
}

struct ContentView: View {
    var body: some View {
        VStack(spacing: 20) {
            Text("중요한 텍스트")
                .emphasized()

            Text("일반 텍스트")
        }
        .padding()
    }
}

✅ 장점

  • 기존 뷰에 체이닝 방식으로 적용 가능 → 선언적 스타일 유지
  • 코드 중복 제거에 효과적
  • 애플도 공식 프레임워크 내부에서 매우 많이 사용 (예: .buttonStyle, .frame 등도 내부적으로 ViewModifier 기반)

❌ 단점

  • 여러 modifier가 중첩되면 구현 추적이 어려울 수 있음

🧑‍💻 사용 예시

  • 버튼, 텍스트, 이미지 등에 스타일을 공통으로 적용할 때
  • 특정 스타일을 추출

🪮 View Style

애플이 제공하는 스타일 프로토콜 (TextFieldStyle, ButtonStyle, ToggleStyle 등)을 구현하여

뷰 구성 요소의 전체적인 인터랙션과 외형을 완전히 바꾸는 방식.

import SwiftUI

struct CustomTextFieldStyle: TextFieldStyle {
    func _body(configuration: TextField<_Label>) -> some View {
        configuration
            .padding(12)
            .background(RoundedRectangle(cornerRadius: 8).stroke(Color.blue, lineWidth: 1))
            .padding(.horizontal)
    }
}

struct ContentView: View {
    @State private var name: String = ""

    var body: some View {
        TextField("이름을 입력하세요", text: $name)
            .textFieldStyle(CustomTextFieldStyle())
    }
}

✅ 장점

  • 시스템 뷰와의 일관성을 유지하면서 동작 방식까지 제어 가능
  • 스타일끼리 쉽게 교체 가능 (다형성)

❌ 단점

  • 적용 대상이 제한적 (예: TextField, Toggle, Button, ProgressView 등)
  • 복잡한 UI 조합에는 부적합

🧑‍💻 사용 예시

  • 앱 전역에서 일관된 스타일을 적용하고자 할 때
  • 특정 컴포넌트 (Button, TextField, etc.)의 기본 동작 및 외형을 커스터마이징할 때

😀 비교

마지막으로 위 내용을 표로 정리해보자.

 

구분  사용 위치 재사용성 특징 대표 예시
struct View 전체 UI ✅ 높음 컴포넌트 단위 분리 카드, 셀, 커스텀 뷰
ViewModifier 스타일 추출 ✅ 중간 선언적 스타일 유지 폰트, 테두리, 그림자
Style 프로토콜 시스템 뷰 스타일링 ✅ 높음 동작 + 외형 변경 TextFieldStyle

출처

https://developer.apple.com/documentation/swiftui/view

 

View | Apple Developer Documentation

A type that represents part of your app’s user interface and provides modifiers that you use to configure views.

developer.apple.com

https://developer.apple.com/documentation/swiftui/viewmodifier

 

ViewModifier | Apple Developer Documentation

A modifier that you apply to a view or another view modifier, producing a different version of the original value.

developer.apple.com

https://developer.apple.com/documentation/swiftui/view-styles

 

View styles | Apple Developer Documentation

Apply built-in and custom appearances and behaviors to different types of views.

developer.apple.com

반응형