SwiftUI 커스텀 폼 컴포넌트 만들기

작성일 :

SwiftUI 커스텀 폼 컴포넌트 만들기

SwiftUI는 애플 생태계에서 앱 개발을 쉽게 하고 빠르게 만들 수 있는 강력한 프레임워크입니다. 이번 글에서는 커스텀 폼 컴포넌트를 SwiftUI로 만드는 법을 다루어 보겠습니다. 커스텀 폼 컴포넌트를 이용하면 코드의 재사용성을 높이고, 일관된 사용자 경험(UX)을 제공할 수 있습니다.

커스텀 폼 컴포넌트의 필요성

폼 컴포넌트는 사용자가 데이터를 입력하거나 선택하는 화면에서 자주 사용됩니다. 하지만 기본 제공되는 폼 컴포넌트만으로는 다양한 요구사항을 모두 충족시키기 어렵습니다. 다행히도 SwiftUI를 사용하면 커스텀 폼 컴포넌트를 쉽게 만들 수 있으며, 이를 통해 원하는 대로 다양한 형태의 입력 방식을 구현할 수 있습니다.

예를 들어, 간단한 로그인 폼에서부터 복잡한 사용자 정보 입력 폼까지 다양한 형태의 폼을 커스텀할 수 있습니다. 이제 간단한 텍스트 필드와 버튼을 포함한 로그인 폼 컴포넌트를 만들어 보겠습니다.

기본적인 SwiftUI 컴포넌트

SwiftUI에는 폼을 만들기 위한 기본 컴포넌트가 많이 제공됩니다. 여기서는 TextField, SecureField, Button 등을 사용하여 간단한 폼을 만들어 보겠습니다.

swift
import SwiftUI

struct LoginForm: View {
    @State private var username: String = ""
    @State private var password: String = ""

    var body: some View {
        VStack {
            TextField("Username", text: $username)
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .padding()
            
            SecureField("Password", text: $password)
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .padding()

            Button(action: {
                print("Username: \(username), Password: \(password)")
            }) {
                Text("Login")
                    .padding()
                    .background(Color.blue)
                    .foregroundColor(.white)
                    .cornerRadius(8)
            }
        }
        .padding()
    }
}

이 컴포넌트는 사용자로부터 usernamepassword를 입력받아, 로그인 버튼을 클릭했을 때 해당 정보를 출력하는 간단한 입력 폼입니다. 이제 이 폼을 더욱 커스텀할 수 있도록 확장해보겠습니다.

커스터마이징 폼 컴포넌트

기본 폼 요소들을 조합하여 더 복잡한 커스텀 폼을 만들어보겠습니다. 여기에서는 다양한 입력 타입을 지원하는 폼을 만들어보겠습니다.

유효성 검사 추가

폼 입력 시 실시간으로 유효성을 검사하여 사용자에게 피드백을 줄 수 있도록 하겠습니다. 이메일 형식 검사와 비밀번호 최소 길이 체크를 추가해 보겠습니다.

swift
import SwiftUI

struct CustomLoginForm: View {
    @State private var email: String = ""
    @State private var password: String = ""
    @State private var isEmailValid: Bool = true
    @State private var isPasswordValid: Bool = true

    var body: some View {
        VStack {
            TextField("Email", text: $email, onEditingChanged: { _ in
                self.isEmailValid = self.isValidEmail(self.email)
            })
            .textFieldStyle(RoundedBorderTextFieldStyle())
            .padding()
            .overlay(RoundedRectangle(cornerRadius: 5)
                        .stroke(self.isEmailValid ? Color.gray : Color.red, lineWidth: 1))

            SecureField("Password", text: $password, onCommit: {
                self.isPasswordValid = self.isValidPassword(self.password)
            })
            .textFieldStyle(RoundedBorderTextFieldStyle())
            .padding()
            .overlay(RoundedRectangle(cornerRadius: 5)
                        .stroke(self.isPasswordValid ? Color.gray : Color.red, lineWidth: 1))

            Button(action: {
                print("Email: \(email), Password: \(password)")
            }) {
                Text("Login")
                    .padding()
                    .background(Color.blue)
                    .foregroundColor(.white)
                    .cornerRadius(8)
            }
        }
        .padding()
    }

    private func isValidEmail(_ email: String) -> Bool {
        let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,64}"
        let emailTest = NSPredicate(format:"SELF MATCHES %@", emailRegEx)
        return emailTest.evaluate(with: email)
    }

    private func isValidPassword(_ password: String) -> Bool {
        return password.count >= 6
    }
}

여기서는 TextFieldSecureField 컴포넌트의 overlay를 사용하여 유효성 검사 결과에 따라 테두리 색상이 변경되도록 했습니다. 각각의 필드가 올바르게 입력되었는지의 여부를 보여줍니다.

커스텀 폼 컴포넌트의 재사용성

앞서 작성한 커스텀 폼 컴포넌트는 이번 프로젝트에만 사용될 것이 아니라, 다른 프로젝트에서도 재사용될 수 있도록 설계되어야 합니다. 이를 위해 컴포넌트를 모듈화하고, 다양한 입력 타입을 지원하는 범용 컴포넌트로 확장할 필요가 있습니다.

모듈화 및 확장 예시

특정 입력값에 대한 유효성 검사를 커스터마이징할 수 있도록 Validator타입을 도입해 봅시다.

swift
import SwiftUI

struct ValidatedTextField: View {
    let title: String
    @Binding var text: String
    var validator: ((String) -> Bool)
    @State private var isValid: Bool = true

    var body: some View {
        TextField(title, text: $text, onEditingChanged: { _ in
            self.isValid = self.validator(self.text)
        })
        .textFieldStyle(RoundedBorderTextFieldStyle())
        .padding()
        .overlay(RoundedRectangle(cornerRadius: 5)
                    .stroke(self.isValid ? Color.gray : Color.red, lineWidth: 1))
    }
}

struct CustomLoginForm: View {
    @State private var email: String = ""
    @State private var password: String = ""

    var body: some View {
        VStack {
            ValidatedTextField(title: "Email", text: $email, validator: isValidEmail)
            ValidatedTextField(title: "Password", text: $password, validator: isValidPassword)

            Button(action: {
                print("Email: \(email), Password: \(password)")
            }) {
                Text("Login")
                    .padding()
                    .background(Color.blue)
                    .foregroundColor(.white)
                    .cornerRadius(8)
            }
        }
        .padding()
    }

    private func isValidEmail(_ email: String) -> Bool {
        let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,64}"
        let emailTest = NSPredicate(format:"SELF MATCHES %@", emailRegEx)
        return emailTest.evaluate(with: email)
    }

    private func isValidPassword(_ password: String) -> Bool {
        return password.count >= 6
    }
}

이제 ValidatedTextField를 사용하여 쉽게 폼 입력을 검증할 수 있으며, 이 컴포넌트를 다른 프로젝트에서도 재사용할 수 있습니다.

결론

SwiftUI를 사용하면 다양한 커스텀 폼 컴포넌트를 쉽게 만들 수 있습니다. 이러한 커스텀 컴포넌트를 통해 일관된 사용자 경험을 제공하고, 코드의 재사용성을 높일 수 있습니다. 이번 글에서는 간단한 예제를 통해 커스터마이징 방법을 살펴보았으나, 실제 프로젝트에서는 더 복잡하고 다양한 요구사항을 충족시키기 위해 추가적인 확장이 필요할 수 있습니다. SwiftUI의 강력한 기능을 활용하여 나만의 커스텀 폼 컴포넌트를 만들어 보세요.