사용자 정의 뷰 수정자를 생성하는 기능은 SwiftUI의 강력한 기능입니다. 이 기사에서는 이 기능을 사용하여 UI 구축을 훨씬 쉽게 만드는 방법에 대한 예를 다룰 것입니다. 의 ViewModifier와 사용자 정의 뷰수정 생성 방법에 익숙하지 않은 경우 여기에서 해당 내용을 읽을 수 있습니다. SwiftUI 이 기사의 목표는 SwiftUI에서 사용자 정의 수정자와 스타일을 생성하는 몇 가지 다양한 방법과 이를 사용하여 깨끗하고 일관된 최종 출력을 달성하면서 UI를 보다 선언적으로 만드는 방법을 다루는 것입니다. 우리가 만들고 싶은 최종 UI는 다음과 같습니다. 화면의 모든 개별 구성 요소를 고려해 보겠습니다. 이미지: 일부 모서리 반경이 있는 표준 이미지 구성요소 텍스트: 제목과 본문 텍스트가 있습니다. 버튼: 전체 너비 버튼 일반 SwiftUI 코드 수정자 없이 이 화면을 빌드하는 경우 코드는 다음과 같습니다. struct ContentView: View { var body: some View { VStack (alignment: .leading) { Image("feature") .resizable() .aspectRatio(contentMode: .fill) .frame(minWidth: 0, maxWidth: .infinity) .frame(height: 220) .cornerRadius(12) .padding(.bottom, 12) Text("Custom ViewModifiers in SwiftUI are the best!") .foregroundColor(Color("titleTextColor")) .font(.system(size: 20, weight: .bold)) .padding(.bottom, 12) Text("Custom ViewModifiers in SwiftUI let you create resuable styles that can be applied to all your views") .foregroundColor(Color("bodyTextColor")) .font(.system(size: 14, weight: .medium)) Spacer() Button(action: { }) { Text("Label") .font(.system(size: 14, weight: .medium)) } .frame(minWidth: 0, maxWidth: .infinity) .padding(.horizontal, 10) .padding(.vertical, 12) .background(Color.blue) .foregroundColor(Color.white) .cornerRadius(12) } .padding(.all, 16) } } 이 접근 방식에는 몇 가지 문제가 있습니다. 일부 요소(예: 제목 및 세부 정보 텍스트)에 대한 스타일은 복제되어야 합니다. 일부 일반적인 스타일(요소 패딩, 모서리 반경 등)에 대한 변경은 여러 위치에서 이루어져야 합니다. 이제 사용자 정의 뷰를 생성하여 UIKit 방식으로 이 문제를 해결할 수 있지만 저는 이 접근 방식을 좋아하지 않습니다. 왜냐하면 내장된 뷰에서 벗어나 새로운 팀 구성원의 온보딩을 더 어렵게 만들기 때문입니다. 더 쉬운 방법은 스타일 자체 대신 적용할 수 있는 일부 범용 뷰 수정자를 정의하는 것입니다. 필요한 일반적인 스타일을 분석해 보겠습니다. 화면 컨테이너: 화면 자체에는 범용 패딩이 있습니다. 이는 선택 사항이지만 모든 화면에 범용 스타일이 있는 것을 선호합니다. 코너 반경 제목 및 본문 텍스트 전체 너비: 항목은 상위 항목(위 예의 버튼 및 이미지) 너비를 채울 수 있어야 합니다. 버튼 스타일링 이미지 크기 조정 사용자 정의 보기 수정자 코너 반경부터 시작해 보겠습니다. struct CommonCornerRadius: ViewModifier { func body(content: Content) -> some View { content .cornerRadius(12) } } 이것은 다소 간단합니다. 요소에 범용 코너 반경을 적용할 수 있습니다. 이를 통해 사용자 정의 뷰를 만들거나 코드베이스 전체에 걸쳐 여러 가지 변경 작업을 수행하지 않고도 전역적으로 앱 스타일을 더 쉽게 변경할 수 있습니다. struct FullWidthModifier: ViewModifier { func body(content: Content) -> some View { content .frame(minWidth: 0, maxWidth: .infinity) } } 이를 통해 전체 너비 보기를 더 쉽게 구현할 수 있으며 더 이상 수동으로 추가할 필요가 없습니다! .frame struct TitleTextModifier: ViewModifier { func body(content: Content) -> some View { content .foregroundColor(Color("titleTextColor")) .font(.system(size: 20, weight: .bold)) } } struct BodyTextModifier: ViewModifier { func body(content: Content) -> some View { content .foregroundColor(Color("bodyTextColor")) .font(.system(size: 14, weight: .medium)) } } 이렇게 하면 일반적인 텍스트 스타일이 허용됩니다. 일반적으로 사용자 정의 텍스트 구성 요소나 유틸리티 함수를 만들고 코드를 통해 UI 구성 요소를 추가합니다. extension Image { func aspectFill() -> some View { self .resizable() .aspectRatio(contentMode: .fill) } } 알겠습니다. 알겠습니다…이것은 사용자 정의 보기 수정자가 아니라 단순한 확장입니다. 이는 ViewModifier가 일반 뷰에 적용되고 과 같은 일부 기능이 이미지에만 적용되기 때문에 확장 기능과 사용자 정의 수정자의 조합을 사용하면 이 문제를 해결하는 데 도움이 됩니다. resizable struct FullWidthButtonStyle: ButtonStyle { func makeBody(configuration: Configuration) -> some View { configuration.label .fullWidth() .foregroundColor(Color.white) .font(.system(size: 14, weight: .medium)) .padding(.horizontal, 10) .padding(.vertical, 12) .background(configuration.isPressed ? Color.blue.opacity(0.2) : Color.blue) } } struct FullWidthButton: ViewModifier { func body(content: Content) -> some View { content .buttonStyle(FullWidthButtonStyle()) } } 마지막으로 이는 버튼에 대한 것입니다. 동일한 효과를 달성하기 위해 단순히 ViewModifier를 생성할 수도 있었지만 탭했을 때 버튼의 모양이 변경되지는 않았습니다. 이는 버튼에 설정하면 탭한 상태와 탭하지 않은 상태 모두에서 해당 배경을 강제로 사용하기 때문입니다. 하면 버튼을 눌렀는지 여부에 따라 버튼의 불투명도를 변경할 수 있습니다. .background ButtonStyle 이제 편의상 다음 수정자를 사용하는 확장을 만드는 것을 좋아합니다. extension View { func commonCornerRadius() -> some View { modifier(CommonCornerRadius()) } func fullWidth() -> some View { modifier(FullWidthModifier()) } func title() -> some View { modifier(TitleTextModifier()) } func body() -> some View { modifier(BodyTextModifier()) } func fullWidthButton() -> some View { modifier(FullWidthButton()) } } extension Image { func aspectFill() -> some View { self .resizable() .aspectRatio(contentMode: .fill) } } 이제 직접 스타일을 지정하는 대신 이를 사용하도록 코드를 변환해 보겠습니다. struct ContentView: View { var body: some View { VStack (alignment: .leading) { Image("feature") .aspectFill() .fullWidth() .frame(height: 220) .commonCornerRadius() .padding(.bottom, 12) Text("Custom ViewModifiers in SwiftUI are the best!") .title() .padding(.bottom, 12) Text("Custom ViewModifiers in SwiftUI let you create resuable styles that can be applied to all your views") .body() Spacer() Button(action: { }) { Text("Awesome") } .fullWidthButton() .commonCornerRadius() } .padding(.all, 16) } } 훨씬 깨끗해요! 언뜻 보기에 이는 단순히 스타일을 수동으로 설정하는 것보다 더 많은 코드와 노력을 필요로 하는 것처럼 느껴지지만 장기적으로는 많은 노력을 절약할 수 있습니다. 개인적으로 이 접근 방식은 뷰별 스타일 기준보다 일반 수정자에 더 의존하여 앱 스타일의 일관성을 높이는 데에도 도움이 됩니다. 그리고 그게 전부입니다! 이것이 앱을 더 빠르고 쉽게 구축하는 데 도움이 되기를 바랍니다. 또 다른 이점은 이러한 수정자를 앱에 추가하고 스타일 지침에 맞게 조정할 수 있다는 것입니다. 나는 또한 이것을 더욱 발전시키기 위해 라이브러리 작업을 해왔습니다. 확인할 수 있습니다. (PS: 이 글을 쓰는 시점에서 라이브러리는 매우 초기 단계에 있으며 저장소는 비어 있습니다. p 하지만 계속 지켜봐 주시기 바랍니다) 여기에서