SwiftUI:如何根据 Picker 的值更新 ForEach 循环的范围
Posted
技术标签:
【中文标题】SwiftUI:如何根据 Picker 的值更新 ForEach 循环的范围【英文标题】:SwiftUI: how to update the range of a ForEach loop based on the value of a Picker 【发布时间】:2020-07-09 17:55:40 【问题描述】:所以我试图让 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 变量与一年中的月份(1 月至 12 月)链接到选择器。这是它的代码:
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()
【问题讨论】:
尽可能提供minimal reproducible example。理想情况下,我们只需复制粘贴即可查看有什么问题。 @pawello2222 我按要求添加了最小可重现示例!唯一需要的就是DetailsView(),但我想因为我只是将其保留为默认的SwiftUI文件而不包含它! 【参考方案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)
【讨论】:
天哪,非常感谢!效果很好!并感谢您重新格式化/清理我的代码!老实说,我不知道您可以像这样拆分视图并将变量用作视图,所以感谢您还教了我一些新东西!以上是关于SwiftUI:如何根据 Picker 的值更新 ForEach 循环的范围的主要内容,如果未能解决你的问题,请参考以下文章