Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How can I create a separate month and year picker in swiftUI?

I’m working on a month and year picker, I want them to be separate, and the order of the months is always the same (January, February etc.) I’ve already managed to create this view, but when I select November, for example, it doesn’t change to November.

I hope you can help me, thank you very much in advance.

This is my MonthPicker code:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

struct MonthPicker: View {
    @ObservedObject var viewModel: CalendarViewModel

    var body: some View {
        Picker("", selection: $viewModel.selectedDate) {
            ForEach(generateMonths(), id: \.self) { monthString in
                Text(monthString)
                    .tag(monthString)
            }
        }
        .labelsHidden()
        // Entfernen Sie den datePickerStyle-Modifikator
        .background(Color.white)
        .cornerRadius(8)
        .overlay(
            RoundedRectangle(cornerRadius: 8)
                .stroke(Color.blue, lineWidth: 1)
        )
        .onChange(of: viewModel.selectedDate, perform: { newDate in
            // Handle month change here
        })
    }

    private func generateMonths() -> [String] {
        let calendar = Calendar.current
        let currentDate = Date()
        var months: [String] = []

        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "MMMM"

        for i in 0..<12 {
            if let date = calendar.date(bySetting: .month, value: i + 1, of: currentDate) {
                let monthString = dateFormatter.string(from: date)
                months.append(monthString)
            }
        }

        return months
    }
}

This is my generateMonths code:

 private func generateMonths() -> [String] {
        let calendar = Calendar.current
        let currentDate = Date()
        let startOfYear = calendar.startOfDay(for: currentDate)
        var months: [String] = []

        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "MMMM"

        for i in 0..<12 {
            if let date = calendar.date(byAdding: .month, value: i, to: startOfYear) {
                let monthString = dateFormatter.string(from: date)
                months.append(monthString)
            }
        }

        return months
    }

And this is how I display the month at the end:

struct test: View {
    @StateObject var viewModel = CalendarViewModel()
    
    
    var body: some View {
        HStack (){
            Spacer()
            MonthPicker(viewModel: viewModel)
                .padding()
                .labelsHidden()
            Spacer()
        }
        
    }
}

This is my CalenderViewModel:

class CalendarViewModel: ObservableObject {
    @Published var selectedDate: Date = Date()
}

>Solution :

To solve this problem, I suggest you create a dedicated structure to represent a month and use it as the value for the Picker.

  • Create a structure for the month: This structure will contain the month name and month number.
  • Modify generateMonths to return a list of these structures.
  • Update the Picker to use this structure as a tag.
  • Ensure that viewModel.selectedDate is correctly updated when the user chooses a month.

struct MonthItem: Identifiable {

    let id: Int 
    let name: String

    init(month: Int, calendar: Calendar = Calendar.current) {
        self.id = month
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "MMMM"
        if let date = calendar.date(bySetting: .month, value: month, of: Date()) {
            self.name = dateFormatter.string(from: date)
        } else {
            self.name = ""
        }
    }
}



private func generateMonths() -> [MonthItem] {

    return (1...12).map { MonthItem(month: $0) }

}

Picker("", selection: $viewModel.selectedMonth) {
    ForEach(generateMonths()) { month in
        Text(month.name).tag(month.id)
    }
}
.onChange(of: viewModel.selectedMonth) { newMonth in
    // Update selectedDate with new selected month
}


 class CalendarViewModel: ObservableObject {
    @Published var selectedMonth: Int // Here, store the number of the selected month
    @Published var selectedDate: Date // Use this date to reflect the selected month and year
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading