SwiftUI:如何基于Picker的值更新ForEach循环的范围

时间:2020-07-09 17:55:40

标签: swift foreach swiftui picker

所以我试图让ForEach循环根据选择的月份(选择器中的值)更新视图循环的次数。就我而言,它们将根据给定年份中所选月份的月份中的天数进行循环。我已经有一个函数可以给我每个月的天数,但是,当我将其插入ForEach循环中时,它只会根据所选的第一个月开始运行,其余的则保持迭代该月的天数。这是我的ForEach循环代码:

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变量与年份中的月份(一月至十二月)链接到选择器。这是它的代码:

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 个答案:

答案 0 :(得分:1)

我清理了一点代码,使代码更具可读性。

这里是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)
    }
}