SwiftUI: как обновить диапазон ForEach l oop на основе значения Picker - PullRequest
1 голос
/ 09 июля 2020

Итак, я пытаюсь обновить ForEach l oop количество раз, когда представление зацикливается в зависимости от того, какой месяц (значение в сборщике) выбран. В моем случае они будут зацикливаться на основе количества дней в месяце выбранного месяца для данного года. У меня уже есть функция, которая дает мне количество дней в каждом месяце, однако, когда я подключаю ее к ForEach L oop, она запускается только на основе выбранного первого месяца и продолжает повторять количество дней этого месяца. что касается прочего. Вот мой код для ForEach L oop:

ForEach(0..<getRange(year: yearIndex, month: monthIndex + indexCheck)) { i in
     NavigationLink(destination: ContentView(day: yearData[yearIndex].months[monthIndex].dayInfo[i])) {
          DayRow(day: yearData[yearIndex].months[monthIndex].dayInfo[i])
     }
}

, а вот функция getRange ():

func getRange(year: Int, month: Int) -> Int {
        return Calendar.current.range(of: .day, in: .month, for: Calendar.current.date(from: DateComponents(year: year + 2020, month: month + 1))!)!.count
}

Переменная yearIndex связана со значением средства выбора трех лет, (2020, 2021, 2022). Вот его код:

Picker("Years", selection: $yearIndex) {
     ForEach(0 ..< year.count) { i in
          Text(String(self.year[i])).tag(i)
     }
}
.pickerStyle(SegmentedPickerStyle())

Переменная monthIndex связана с сборщиком месяцев в году (Янв-Де c). Вот его код:

Picker("Month", selection: $monthIndex) {
     ForEach(0 ..< monthArray.count) { i in
          Text(self.monthArray[i]).tag(i)
     }
}
.padding(.bottom, 2)

Я не уверен, что делаю неправильно, и я не уверен, как это сделать, поэтому любая помощь будет принята с благодарностью! Я все еще новичок в Swift / SwiftUI, поэтому любые советы по улучшению этого кода также будут оценены!

РЕДАКТИРОВАТЬ: Вот минимальный воспроизводимый пример по запросу:

struct ContentView: View {
    
    @State var year = [2020, 2021, 2022]
    //monthSymbols gets an array of all the months
    @State var monthArray = DateFormatter().monthSymbols!
    @State var yearIndex = 0
    @State var monthIndex = 0
    @State var indexCheck = 0
    @State var indexTest = 0
    
    var body: some View {
        NavigationView {
            List {
                Section {
                    VStack {
                        Picker("Years", selection: $yearIndex) {
                            ForEach(0 ..< year.count) { i in
                                Text(String(self.year[i])).tag(i)
                            }
                        }
                        .pickerStyle(SegmentedPickerStyle())
                        
                        Divider()
                        
                            Picker("Month", selection: $monthIndex) {
                                ForEach(0 ..< monthArray.count) { i in
                                    Text(self.monthArray[i]).tag(i)
                                }
                            }
                            .padding(.bottom, 2)
                        }
                    }
                    Section(header: Text("What I love about you")) {
                        ForEach(0..<getRange(year: yearIndex, month: monthIndex + indexCheck)) { i in
                            NavigationLink(destination: DetailsView()) {
                                Text("Row \(i)")
                            }
                        }
                    }
            }
            .listStyle(InsetGroupedListStyle())
            .navigationBarTitle(Text("\(monthArray[monthIndex + indexCheck]) \(String(year[yearIndex]))"))
        }
        
    }
    func getRange(year: Int, month: Int) -> Int {
        return Calendar.current.range(of: .day, in: .month, for: Calendar.current.date(from: DateComponents(year: year + 2020, month: month + 1))!)!.count
    }
}

struct YearView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

1 Ответ

1 голос
/ 09 июля 2020

Я немного почистил ваш код, чтобы он был более читабельным.

Вот ContentView:

struct ContentView: View {
    let yearArray = [2020, 2021, 2022]
    let monthArray = DateFormatter().monthSymbols!

    // you don't need to operate on indices, you can use real values
    @State var selectedYear = 2020
    @State var selectedMonth = 1

    // improved readability
    var combinedYearMonth: String {
        "\(monthArray[selectedMonth - 1]) \(selectedYear)"
    }

    var body: some View {
        NavigationView {
            List {
                pickerSection
                daySelectionSection
            }
            .listStyle(InsetGroupedListStyle())
            .navigationBarTitle(combinedYearMonth)
        }
    }
}

Часть, отвечающая за отображение разделов списка:

// sections extracted to a private extension (you can still have everything in one `ContentView` struct if you want)
private extension ContentView {
    var pickerSection: some View {
        Section {
            yearPicker
            monthPicker
        }
    }

    var daySelectionSection: some View {
        Section(header: Text("What I love about you")) {
            ForEach(dayRange, id: \.self) { day in
                NavigationLink(destination: DetailsView()) {
                    Text("Day \(day)")
                }
            }
        }
    }

    // create a range of days in the `selectedMonth` for the `selectedYear`
    var dayRange: Range<Int> {
        let dateComponents = DateComponents(year: selectedYear, month: selectedMonth)
        let calendar = Calendar.current
        let date = calendar.date(from: dateComponents)!
        return calendar.range(of: .day, in: .month, for: date)!
    }
}

И часть с сборщиками:

private extension ContentView {
    var yearPicker: some View {
        Picker("Years", selection: $selectedYear) {
            ForEach(yearArray, id: \.self) { year in
                Text(String(year)) // <- no need for `.tag()` if the `id` parameter in `ForEach` is specified
            }
        }
        .pickerStyle(SegmentedPickerStyle())
    }

    var monthPicker: some View {
        Picker("Month", selection: $selectedMonth) {
            ForEach(1...12, id: \.self) { month in
                Text(self.monthArray[month - 1])
            }
        }
        .padding(.bottom, 2)
    }
}
...