You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中如何持久化收藏按钮的颜色状态?

问题解决:SwiftUI收藏按钮状态持久化及颜色同步

问题根源

你当前使用@State private var isFavorited = false存储按钮状态,@State是临时内存状态,应用重启后会重置。同时你的代码中isFavorited和favorites的状态存在同步断层,导致UI状态无法跟随持久化数据更新。

解决方案步骤

1. 实现Favorites类的持久化

确保收藏数据能保存到本地,重启后自动加载。这里使用UserDefaults实现轻量持久化,要求Character遵循Codable协议。

import SwiftUI

class Favorites: ObservableObject {
    @Published var characters: [Character] = []
    private let saveKey = "FavoriteCharacters"
    
    init() {
        // 初始化时从UserDefaults加载数据
        if let savedData = UserDefaults.standard.data(forKey: saveKey) {
            if let decodedCharacters = try? JSONDecoder().decode([Character].self, from: savedData) {
                characters = decodedCharacters
                return
            }
        }
        characters = []
    }
    
    // 判断角色是否已收藏
    func contains(_ character: Character) -> Bool {
        characters.contains { $0.id == character.id } // 假设Character有唯一id属性
    }
    
    // 添加收藏
    func add(_ character: Character) {
        guard !contains(character) else { return }
        characters.append(character)
        saveToDefaults()
    }
    
    // 取消收藏
    func remove(_ character: Character) {
        characters.removeAll { $0.id == character.id }
        saveToDefaults()
    }
    
    // 保存到UserDefaults
    private func saveToDefaults() {
        if let encodedData = try? JSONEncoder().encode(characters) {
            UserDefaults.standard.set(encodedData, forKey: saveKey)
        }
    }
}

// 确保Character遵循Codable和Identifiable协议
struct Character: Identifiable, Codable {
    let id: Int
    let name: String
    let image: String
    // 其他属性根据需求补充
}

2. 修改CharacterDetailsView,移除临时状态

用基于favorites的计算属性替代@State,让UI状态完全依赖持久化数据:

struct CharacterDetailsView: View {
    var character: Character
    @EnvironmentObject var favorites: Favorites
    
    // 直接从持久化的favorites中获取状态
    private var isFavorited: Bool {
        favorites.contains(character)
    }
    
    var favoriteText: String {
        isFavorited ? "Favorited" : "Favorite"
    }
    
    var favoriteButton: some View {
        Button {
            // 直接操作favorites,计算属性会自动同步UI
            isFavorited ? favorites.remove(character) : favorites.add(character)
        } label: {
            ZStack {
                Capsule()
                    .strokeBorder(isFavorited ? Color.blue : Color.green, lineWidth: 4)
                    .frame(width: 250, height: 50)
                    .background(
                        Capsule()
                            .fill(isFavorited ? Color.blue : Color.green)
                            .cornerRadius(20)
                    )
                
                HStack {
                    Text(favoriteText)
                        .foregroundColor(.white)
                    Image(systemName: isFavorited ? "heart.fill" : "heart")
                        .foregroundColor(.white)
                }
            }
        }
        .padding(.vertical)
    }
    
    var body: some View {
        ScrollView {
            VStack {
                AsyncImage(url: URL(string: character.image)) { phase in
                    if let image = phase.image {
                        image
                            .resizable()
                            .scaledToFit()
                    } else if phase.error != nil {
                        Text("无法加载图片")
                    } else {
                        ProgressView()
                    }
                }
                
                VStack(alignment: .leading) {
                    Text(character.name)
                        .font(.largeTitle)
                        .bold()
                        .padding(.leading)
                    
                    favoriteButton
                }
            }
        }
    }
}

核心优化点

  • 移除临时@State变量,UI状态完全绑定到持久化的favorites数据,重启后自动恢复
  • Favorites类负责数据的加载与保存,确保收藏状态持久化
  • 按钮的颜色、文本、图标统一依赖isFavorited计算属性,避免状态不同步问题

内容的提问来源于stack exchange,提问作者Kevin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 03:06:29