본문 바로가기

프로젝트/ReminderApp clone

02. 새 List 추가 인터페이스 구현하기

DB에 새로운 List를 추가하기 위해 List를 추가하는 인터페이스를 작성한다.
애플의 Reminder와는 일단은 다르지만 기본적인 기능을 수행할 수 있도록 최소한으로 작성했다.

//
//  ColorPickerView.swift
//  ReminderApp
//

import SwiftUI

struct ColorPickerView: View {
    
    @Binding var selectedColor: Color
    
    let colors: [Color] = [.red, .green, .blue, .yellow, .orange, .purple]
    
    var body: some View {
        HStack {
            ForEach(colors, id: \.self) { color in
                ZStack {
                    Circle().fill()
                        .foregroundColor(color)
                        .padding(2)
                    Circle()
                        .strokeBorder(selectedColor == color ? .gray : .clear, lineWidth: 4)
                        .scaleEffect(CGSize(width: 1.2, height: 1.2))
                }
                .onTapGesture {
                    selectedColor = color
                }
            }
        }
        .padding()
        .clipShape(RoundedRectangle(cornerRadius: 10.0, style: .continuous))
        .frame(maxWidth: .infinity, maxHeight: .infinity)
    }
}

화면 하단의 ColorPicker는 위와 같이 구현했다.
주목해야 할 점은 원형 인터페이스의 구현 부분으로

ZStack {
    Circle().fill()
        .foregroundColor(color)
        .padding(2)
    Circle()
        .strokeBorder(selectedColor == color ? .gray : .clear, lineWidth: 4)
        .scaleEffect(CGSize(width: 1.2, height: 1.2))
}
.onTapGesture {
    selectedColor = color
}

ColorWell과 SelctIndicator를 ZStack으로 구현한 것이 특징이다.
SelectIndicator를 조건부로 표시하지 않고, 항상 존재하도록 구현하고, 색상만 투명한 색으로 교체하는 방식은 인터페이스의 크기를 고정해 토글 됐을 때 레이아웃이 변경되는 문제를 해결할 수 있다.

//
//  AddNewListView.swift
//  ReminderApp
//

import SwiftUI

struct AddNewListView: View {
    
    @Environment(\.dismiss) private var dismiss
    @State private var name: String = ""
    @State private var selectedColor: Color = .yellow
    
    let onSave: (String, UIColor) -> Void
    
    private var isFormValid: Bool {
        !name.isEmpty
    }
    
    var body: some View {
        VStack {
            VStack {
                Image(systemName: "line.3.horizontal.circle.fill")
                    .foregroundColor(.green)
                    .font(.system(size: 100))
                
                TextField("List Name", text: $name)
                    .multilineTextAlignment(.center)
                    .textFieldStyle(.roundedBorder)
            }
            .padding(30)
            .clipShape(RoundedRectangle(cornerRadius: 10.0, style: .continuous))
            
            ColorPickerView(selectedColor: $selectedColor)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
        .toolbar {
            ToolbarItem(placement: .principal) {
                Text("New List")
                    .font(.headline)
            }
            
            ToolbarItem(placement: .topBarLeading) {
                Button("Close") {
                    dismiss()
                }
            }
            
            ToolbarItem(placement: .topBarTrailing) {
                Button("Done") {
                    
                    // TODO: save function
                    onSave(name, UIColor(selectedColor))
                    
                    dismiss()
                }
                .disabled(!isFormValid)
            }
        }

    }
}

나머지 인터페이스의 구성은 특별한 부분 없다.