我正在尝试实现一个 View ,该 View 可以在内容数组的大小发生变化时更改显示项目的数量(由 ForEach 循环创建),就像购物应用程序可能会在用户下拉刷新后更改其可用项目的数量一样
这是我到目前为止尝试过的一些代码。如果我没记错的话,这些适用于 Xcode beta 4,但适用于 beta 5:
- 如果数组的大小增加,循环仍将显示原始数量的元素
- 数组的大小减小会导致索引超出范围错误
代码:
import SwiftUI
struct test : View {
@State var array:[String] = []
@State var label = "not pressed"
var body: some View {
VStack{
Text(label).onTapGesture {
self.array.append("ForEach refreshed")
self.label = "pressed"
}
ForEach(0..<array.count){number in
Text(self.array[number])
}
}
}
}
#if DEBUG
struct test_Previews: PreviewProvider {
static var previews: some View {
test()
}
}
#endif
一般来说,我是 SwiftUI 和 GUI 编程的新手,感觉每个内容都是在启动时定义的,之后很难进行更改(例如:在用户导航离开然后返回后重置 View ) .非常感谢循环问题的解决方案或使 View 更具动态性的任何提示!
最佳答案
Beta 5 发行说明说:
您应该更改 ForEach
以接收一个数组,而不是范围。理想情况下是 Identifiable
数组,以避免使用 \.self
。但根据您的目标,这仍然有效:
import SwiftUI
struct ContentView : View {
@State var array:[String] = []
@State var label = "not pressed"
var body: some View {
VStack{
Text(label).onTapGesture {
self.array.append("ForEach refreshed")
self.label = "pressed"
}
ForEach(array, id: \.self) { item in
Text(item)
}
}
}
}
或者按照rob mayoff的建议,如果您需要索引:
struct ContentView : View {
@State var array:[String] = []
@State var label = "not pressed"
var body: some View {
VStack{
Text(label).onTapGesture {
self.array.append("ForEach refreshed")
self.label = "pressed"
}
ForEach(array.indices, id: \.self) { index in
Text(self.array[index])
}
}
}
}
关于swift - 如何在数组大小更改后刷新 ForEach 显示元素的数量(SwiftUI、Xcode 11 Beta 5),我们在Stack Overflow上找到一个类似的问题: swift - How to refresh number of ForEach's displaying elements after array's size changes (SwiftUI, Xcode 11 Beta 5) - Stack Overflow
具有非恒定范围视图刷新的Swift ForEach
swift view swiftui-foreach
我知道这是一个简单的问题,但我还没有找到答案。我想了解基本概念。
我试图用非常量范围更新ForEach,closing参数是分配给按钮的变量。
变量被赋予@状态,因此应该刷新视图。不知怎么的,它不起作用了。
import SwiftUI
struct ContentView: View {
@State private var numberOfTimes = 5
let timesPicker = [2,5,10,12,20]
@State private var tableToPractice = 2
enum answerState {
case unanswered
case wrong
case right
}
func listRange(){
}
var body: some View {
NavigationView{
HStack{
VStack{
Form{
Section {
Picker("Tip percentage", selection: $numberOfTimes) {
ForEach(timesPicker, id: \.self) {
Text($0, format: .number)
}
}
.pickerStyle(.segmented)
} header: {
Text("How many times do you want to practice?")
}
Section{
Stepper("Table to practice: \(tableToPractice.formatted())", value: $tableToPractice, in: 2...16 )
}
Button("Start Now", action: listRange).buttonStyle(.bordered)
List{
ForEach(0..<numberOfTimes){
Text("Dynamic row \($0)")
}
}
}.foregroundColor(.gray)
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
发布于 1 年前
✅ 最佳回答:
问题是没有确定范围。让我们排几行
struct Row: Identifiable {
let id = UUID()
}
然后设置一组可识别的项目
@State private var numberOfTimes = 5
@State private var rows = Array(repeating: Row(), count: 5)
现在,您可以获得响应列表
List{
ForEach(rows) { row in
Text("Dynamic row")
}
}
调用更改时更新以重新创建阵列
.onChange(of: numberOfTimes) { newValue in
rows = Array(repeating: Row(), count: newValue)
numberOfTimes = newValue
}
应在表单上调用onChange。
当您能够更好地查看模型数据时,这将更有意义,有关更深入的示例,请参阅apple文档。
这是针对lazy v stack的,但我考虑的是数据模型设置
https://developer.apple.com/documentation/swiftui/grouping-data-with-lazy-stack-views
最终解决办法:将FOREACH的列表改为@Published属性即可。