所以我试图让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()
}
}
答案 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)
}
}