ios – How to take user input for date of birth in DD MM YYYY format? SwiftUI

0
49


I want to build a signup screen in which user needs to input date of birth in DD MM YYYY format, something like the image below.

enter image description here

I’m creating a single enum for input textfields and the code looks like

struct Test: View {
    
    @StateObject var testViewModel: TestViewModel = .init()
    
    @FocusState var activeField: BirthdayFields?
    
    var body: some View {
        
        ZStack {
            
            Color.black.ignoresSafeArea()
            
            VStack {
                
                Spacer()
                
                BirthdayField()
                    .padding()
                
                
                Button{Task {await testViewModel.letsDate()}}
                       label: {
                    Text("Birthday")
                        .keyboardType(.numberPad)
                        .padding()
                        .frame(maxWidth: .infinity)
                        .background{
                            RoundedRectangle(cornerRadius: 10, style: .continuous)
                                .fill(.yellow)
                        }
                }
                .disabled(checkStates())
                .opacity(checkStates() ? 0.4 : 1)
                
                Spacer()
                
            }
            .onChange(of: testViewModel.dobFields) { newValue in
               DOBConditions(value: newValue)
            }
            
        }
        
    }
    
    @ViewBuilder
    func BirthdayField() -> some View {
        
        HStack(spacing: 6) {
            
            ForEach(0..<8, id: \.self) { index in
                
                VStack {
                    
                    TextField("D", text: $testViewModel.dobFields[index])
                        .foregroundColor(.gray)
                        .keyboardType(.numberPad)
                        .textContentType(.dateTime)
                        .multilineTextAlignment(.center)
                        .focused($activeField, equals: activeStateForIndex(index: index))
                        .onAppear{
                            DispatchQueue.main.async {
                                activeField = activeStateForIndex(index: index)
                            }
                        }
                    
                    
                    Rectangle()
                        .fill(activeField == activeStateForIndex(index: index) ? .blue : .gray.opacity(0.4))
                        .frame( height: 4)
                    
                }
                
            }
            
        }
        
    }
    
    func checkStates() -> Bool {
        for index in 0..<8{
            if testViewModel.dobFields[index].isEmpty{return true}
        }
        return false
    }
    
    func activeStateForIndex(index: Int) -> BirthdayFields {
        switch index {
        case 0: return .field1
        case 1: return .field2
        case 2: return .field3
        case 3: return .field4
        case 4: return .field5
        case 5: return .field6
        case 6: return .field7
        default: return .field8
        }
    }
    
    enum BirthdayFields {
        case field1
        case field2
        case field3
        case field4
        case field5
        case field6
        case field7
        case field8
    }
    
    func DOBConditions(value: [String]) {
        
        for index in 0..<8{
            if value[index].count == 8{
                DispatchQueue.main.async {
                    testViewModel.dobText = value[index]
                    testViewModel.dobFields[index] = ""
                }
                return
            }
        }
        
        // moving next field if current field type
        for index in 0..<7{
            if value[index].count == 1 && activeStateForIndex(index: index) == activeField {
                activeField = activeStateForIndex(index: index + 1)
            }
        }
        
        // moving back if current is empty and previous is not empty
        for index in 1...7{
            if value[index].isEmpty && !value[index - 1].isEmpty{
                activeField = activeStateForIndex(index: index - 1)
            }
        }
        
        // limiting only one text
        for index in 0..<8{
            if value[index].count > 1{
                testViewModel.dobFields[index] = String(value[index].last!)
            }
        }
        
    }
    
}

The result looks like below image

enter image description here

My question is, how can I achieve the DD MM YYYY format? Should I create separate enums for date, month, and year? And how does moving to next field or deleting the previous ones work in that case?