SwiftUI按钮状态反馈和延时恢复场景
SwiftUI按钮状态反馈和延时恢复场景

SwiftUI按钮状态反馈和延时恢复场景

使用场景

在SwiftUI中,我想要实现点击“下载”按钮后,下载图片并显示下载完成,等待2秒钟后恢复“下载”文字。

我先考虑的解决方案有两种:

1、设置一个Set数组,存储每一个图片的下载状态,如果点击下载后,图片状态改为true,等待2秒后再修改为false.

2、在Button变量内创建一个局部变量,点击下载按钮,局部变量改为true,等待2秒后修改为false。

但这两种方案经过思考后,都不是非常合适。

解决方案

1、修改图片模型CustomImages

为每张图片的“下载按钮状态”设置一个单独变量:

class CustomImages: ObservableObject, Identifiable {
    let id: UUID
    let image: NSImage
    @Published var isDownloaded: Bool = false // 新增字段
}

2、修改下载按钮逻辑

Button(action: {
    DownloadImage() // 下载图片的方法
    item.isDownloaded = true

    // 延时 2 秒后恢复
    DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
        item.isDownloaded = false
    }
}) {
    if item.isDownloaded {
        Image(systemName:"checkmark")
            .foregroundColor(.green)
            .padding(.vertical, 5)
            .padding(.horizontal, 20)
            .background(Color(hex: "DFF0D8"))
            .cornerRadius(20)
    } else {
        Text("Download")
            .foregroundColor(Color(hex: "3679F6"))
            .padding(.vertical, 5)
            .padding(.horizontal, 20)
            .background(Color(hex: "EEEEEE"))
            .cornerRadius(20)
    }
}

总结

在模型中新增下载状态字段,可以实现状态跟随对象,绑定更简单,容易维护。

扩展知识

按钮视图没有变化

如果按钮视图没有根据isDownloaded变量切换按钮的显示,可能遇到的是SwiftUI的限制:

如果使用的是 @Published,那么只负责追踪变量本身的变化,而不会深入追踪数组内部每个元素的变化(哪怕这些元素是 ObservableObject)。

class AppStorage:ObservableObject {
    static var shared = AppStorage()
    // 存储图片
    @Published var images:[CustomImages] = []   // 图片数组
}

所以即使 CustomImages 是 class、在里面加了 @Published var isDownloaded = false,也不等于 @Published var images 能感知这个变化。

这意味着:

images.append(…) 会触发刷新(数组结构变化)。

images.remove(…) 会触发刷新(结构变化)。

images[0].isDownloaded = true 不会刷新(结构没变,SwiftUI不会重新渲染)。

因此,就需要创建按钮的子视图,并绑定具体的实例:

import SwiftUI

struct ImageRowView: View {
    @ObservedObject var item: CustomImages
    var completion: () -> Void
    
    var body: some View {
        Button(action: {
            completion()
            print("isDownloaded状态改为true")
            item.isDownloaded = true
                // 延时 2 秒后恢复
                DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
                    print("isDownloaded状态改为false")
                    item.isDownloaded = false
                }
        }) {
            if item.isDownloaded {
                Image(systemName:"checkmark")
            } else {
                Text("Download")
            }
        }
    }
}

在SwiftUI中,绑定按钮子视图:

// 下载按钮
ImageRowView(item: item) {
    saveToDownloads(file: item)
}

这样 SwiftUI 才能正确追踪这个 item 的 @Published 属性。

   

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开发者。

欢迎加入我们的 微信交流群QQ交流群,交流更多精彩内容!
微信交流群二维码 QQ交流群二维码

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注