swift - 如何在数组大小更改后刷新 ForEach 显示元素的数量(SwiftUI、Xcode 11 Beta 5)

我正在尝试实现一个 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 发行说明说:

The retroactive conformance of Int to the Identifiable protocol is removed. Change any code that relies on this conformance to pass .self to the id parameter of the relevant initializer. Constant ranges of Int continue to be accepted:

lang-swift 复制代码
List(0..<5) {
   Text("Rooms")
}

However, you shouldn't pass a range that changes at runtime. If you use a variable that changes at runtime to define the range, the list displays views according to the initial range and ignores any subsequent updates to the range.

您应该更改 ForEach 以接收一个数组,而不是范围。理想情况下是 Identifiable 数组,以避免使用 \.self。但根据您的目标,这仍然有效:

lang-swift 复制代码
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的建议,如果您需要索引:

lang-swift 复制代码
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属性即可。

相关推荐
小蜜蜂嗡嗡5 小时前
【flutter项目从xcode运行时报错:Undefined symbol: _OBJC_CLASS_$_WeiboSDK】
flutter·cocoa·xcode
360智汇云2 天前
智汇云API市场:大模型流式语音识别
人工智能·语音识别·xcode
询问QQ688238863 天前
大子刊nc复现:‘在连续介质中束缚态驱动下的最大和可调谐手征光学响应的平面手征超表面‘——涉及...
xcode
z***y8626 天前
Swift在iOS中的Xcode
ios·xcode·swift
Q688238866 天前
Comsol仿真金属纳米颗粒超表面的多极分解之旅
xcode
许泽宇的技术分享9 天前
用 OpenAI Whisper + pyannote.audio 打造“谁在说什么”的全栈语音理解系统
macos·whisper·xcode
2501_9417987310 天前
C++高性能音频处理与实时特征提取实战分享:多线程信号处理与低延迟优化经验
ide·macos·xcode
Morgan-Chen10 天前
iOS开发针对苹果新系统iOS26的兼容适配
ios·objective-c·xcode·ios26
denggun1234516 天前
Xcode的App Thinning Size Report分析包体积
macos·蓝桥杯·xcode
枫子有风17 天前
【go.sixue.work】2.2 面向对象:接口与多态
开发语言·后端·golang·xcode