swift - 如何在通过算法连续更改 View 状态时动态重新渲染 View ?

标签 swift swiftui

我有一个 View 显示标记为 @State 属性的数组的值。 当例如我有一个用于对数组进行排序的按钮,我如何实现 SwiftUI 为排序算法中改变数组值的每个步骤更新屏幕?

在这个测试示例中,我制作了一个使用冒泡排序对数组进行排序的按钮:

struct ContentView: View {
    
    @State private var array = [5,3,6,9,1,2,4,13,3,4,16]
    
    var body: some View {
        
        HStack {
            ForEach(0..<array.count, id: \.self) { i in
                Text("\(array[i])").padding()
            }
        }
        
        Button("Sort") {
            var j = array.count
            while j >= 1 {
                for i in 1..<j {
                    if array[i] < array[i-1] {
                        let temp = array[i-1]
                        array[i-1] = array[i]
                        array[i] = temp
                    }
                }
                sleep(1) // to compensate for the short runtime in this example 
                j -= 1
            }
        }
    }
}

尽管 @State 属性在每个排序步骤中都会发生变化,但为什么 SwiftUI 只重新渲染 View 一次? 是否有可能以某种方式在屏幕上可视化每个步骤,而不仅仅是看到算法的最终结果?

我希望此行为在运行类似于数独求解器的程序时可视化回溯步骤。在此先感谢您的帮助!

PS:我对 Swift/SwiftUI 很陌生,这也是我在 Stack Overflow 上的第一个问题。如果我不够具体或遗漏了一些明显的东西,我深表歉意!

最佳答案

通过使用sleep,您将阻塞主线程并阻止 UI 更新。相反,您可以使用 DispatchQueue.main.asyncAfter 运行排序的每个连续步骤:


struct ContentView: View {
    
    @State private var array = [5,3,6,9,1,2,4,13,3,4,16]
    @State private var currentElement = 0
    
    var body: some View {
        
        HStack {
            ForEach(array, id: \.self) { i in
                Text("\(i)").padding()
            }
        }
        
        Button("Sort") {
            currentElement = array.count
            withAnimation {
                runSortStep()
            }
        }
    }
    
    func runSortStep() {
        for i in 1..<currentElement {
            if array[i] < array[i-1] {
                let temp = array[i-1]
                array[i-1] = array[i]
                array[i] = temp
            }
        }
        currentElement -= 1
        if currentElement >= 1 {
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                withAnimation {
                    runSortStep()
                }
            }
        }
    }
}

请注意,我还更改了您的 ForEach,以便每个元素都由数组值而非索引标识——否则,您将看不到动画。

关于swift - 如何在通过算法连续更改 View 状态时动态重新渲染 View ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68399759/

相关文章:

swift - 如何在不丢失导航栏 UI 的情况下更改我的 SwiftUI 背景?

SwiftUI 2.0 如何更改表单部分的背景颜色

text - SwiftUI-文本minimumScaleFactor不会仅在需要时缩放

swift - 从 UIColor 获取色调会产生错误的结果

ios - 将参数传递给实现协议(protocol)并快速扩展类的方法

swift - 实现符合 Hashable 协议(protocol)的通用结构。错误 : Refernce to generic type 'strA' requires arguments in <. ..> 错误

swift - 使用多个按钮自定义警报 View

swift - 如果在表格 View 中选中复选框,如何保存选定的数组

ios - swift 用户界面 : How to Fix leading and trailing with margin 10

ios - SwiftUI 选择器值在超出最大值时重置