본문 바로가기

프로젝트/Twitter Clone App (w∕Firebase)

08. 기본 UI 구현하기 #8

기본 UI 구현하기 #8
CustomTextField & AuthHeaderView & RegistrationView


CustomTextField

더보기

Source

VStack(spacing: 40) {
    TextField("Email", text: $email)

    SecureField("Password", text: $password)
}
.padding(.horizontal, 32)
.padding(.top, 44)

LoginView에서 사용했던 두 개의 TextField는
이미지와 TextField 혹은 SecureField, Divider의 조합으로 이루어져 있다.
같은 UI가 동일하게 RegistrationView에서도 사용되기 때문에 재사용을 용이하게 하기 위해 모듈화 한다.

더보기

Source

struct CustomTextField: View {
    let imageName: String
    let placeholderText: String
    let fieldType: FieldType

    @Binding var text: String

    enum FieldType {
        case normal
        case secure
    }

    var body: some View {
        VStack {
            HStack {
                Image(systemName: imageName)
                    .resizable()
                    .scaledToFit()
                    .frame(width: 20, height: 20)
                    .foregroundColor(Color(.darkGray))

                if fieldType == .secure {
                    SecureField(placeholderText, text: $text)
                } else {
                    TextField(placeholderText, text: $text)
                }
            }

            Divider()
                .background(Color(.darkGray))
        }
    }
}

해당 CustomView는 systemName에 해당하는 imageName,
placeholder에 해당하는 placeholderText,
TextField의 타입에 해당하는 fieldType 세 개의 파라미터를 갖는다.

fieldType에 따라 SecureField 혹은 TextField를 사용해 UI를 구성한다.
파라미터로 직접 systemName을 받기 때문에 id나 pw 외의 값을 입력받는 데에도 사용할 수 있다는 것이 장점이다.

AuthHeaderView

LoginView와 RegistrationView는 상단의 문구만 다르지 동일한 UI를 가지고 있다.
이 부분도 재사용하기 위해 별도로 분리하면 유지보수에 조금 더 유리할 수 있다.

더보기

Source

struct AuthHeaderView: View {
    let upperTitle: String
    let lowerTitle: String

    var body: some View {
        VStack(alignment: .leading) {
            HStack {
                Spacer()
            }

            Group {
                Text(upperTitle)

                Text(lowerTitle)
            }
            .font(.largeTitle)
            .fontWeight(.semibold)
        }
        .frame(height: 260)
        .padding(.leading)
        .background(Color(.systemBlue))
        .foregroundColor(.white)
        .clipShape(RoundedShape(corners: .bottomRight))
    }
}

해당 CustomView는 upperTitle과 lowerTitle 두 개의 파라미터로 설정할 문자열을 받아
정해진 디자인대로 배치한다.

RegistrationView

RegistrationView는 LoginView와 거의 동일한 UI를 가지고,
앞서 많은 부분을 재사용할 수 있도록 모듈화 해 놓았기에 배치만 조금 수정해 주면 된다.

더보기

Source

struct RegistrationView: View {
    @Environment(\.dismiss) var dismiss

    @State private var email = ""
    @State private var password = ""
    @State private var userName = ""
    @State private var fullName = ""

    var body: some View {
        VStack {
            AuthHeaderView(upperTitle: "Get started.", lowerTitle: "Create your account")

            VStack(spacing: 40) {
                CustomTextField(imageName: "envelope", placeholderText: "Email", fieldType: .normal, text: $email)

                CustomTextField(imageName: "person", placeholderText: "UserName", fieldType: .normal, text: $userName)

                CustomTextField(imageName: "person", placeholderText: "FullName", fieldType: .normal, text: $fullName)

                CustomTextField(imageName: "lock", placeholderText: "Password", fieldType: .normal, text: $password)
            }
            .padding(32)

            Button {
                print("signup function")
            } label: {
                Text("Sign Up")
                    .font(.headline)
                    .foregroundColor(.white)
                    .frame(width: 340, height: 50)
                    .background(Color(.systemBlue))
                    .clipShape(Capsule())
                    .padding()
            }
            .shadow(color: .gray.opacity(0.5), radius: 10)

            Spacer()

            Button {
                dismiss()
            } label: {
                HStack {
                    Text("Already have an account?")

                    Text("Sign In")
                        .fontWeight(.semibold)
                }
                .foregroundColor(Color(.systemBlue))
                .font(.footnote)
            }
            .padding(32)
        }
        .ignoresSafeArea()
        .toolbar(.hidden)
    }
}

 

동작은 다음과 같이 된다.
각자의 View에 서로 NavigationLink 혹은 dismiss가 동작하므로 자연스럽게 전환된다.

'프로젝트 > Twitter Clone App (w∕Firebase)' 카테고리의 다른 글

10. 기능 구현하기 #2  (0) 2022.12.20
09. 기능 구현하기 #1  (0) 2022.12.13
07. 기본 UI 구성하기 #7  (0) 2022.12.02
06. 기본 UI 구성하기 #6  (0) 2022.12.01
05. 기본 UI 구성하기 #5  (0) 2022.11.30