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

SwiftUI点击New Game按钮后卡片视图未更新问题解决

问题根因

点击New Game按钮不生效是4个代码逻辑问题共同导致的:

  • ContentView中声明的MemoryGameTheme实例没有加状态包装器,SwiftUI不会跟踪该属性的变化,且按钮回调里调用的onActivate()方法不存在,点击后没有触发游戏模型重建。
  • MemoryGameTheme中所有主题相关属性都被定义为static静态属性,修改静态属性不会触发ObservableObject的更新通知,视图无法感知主题变化。
  • 点击按钮后仅调用了主题刷新方法,没有通知EmojiMemoryGame用新主题重新生成卡片数组,旧的卡片数据一直被@Published持有,自然不会更新。
  • 主题名称显示直接读取类的静态属性,不会跟着当前选中的主题动态变化,卡片颜色也写死为红色,没有适配主题配置。
修复方案

MemoryGame结构体的配对、翻牌逻辑本身没有问题,只需要修改主题类、游戏视图模型、主视图三个文件的逻辑即可。

1. 重构MemoryGameTheme类

删除静态属性,改用@Published标记的实例属性,保证属性更新时能自动触发视图刷新:

import SwiftUI

class MemoryGameTheme: ObservableObject {
    enum ChoiseTheme: CaseIterable {
        case car, animal, item, food, face
    }
    
    @Published var choiseTheme: [String]
    @Published var themeName: String
    @Published var colorCard: Color
    
    init() {
        // 初始默认加载动物主题
        self.choiseTheme = ["🐣", "🙉", "🙊", "🙈", "🐵", "🐽", "🐸", "🦊", "🐨", "🐹", "🐰", "🐻", "🐼", "🐻‍❄️", "🐶", "🐱", "🐮"]
        self.themeName = "Animals"
        self.colorCard = .gray
        // 初始化时随机选择主题
        refreshTheme()
    }
    
    private func theme(for selectedTheme: ChoiseTheme) {
        switch selectedTheme {
        case .car:
            choiseTheme = ["🚗", "🚕", "🚙", "🚌", "🚎", "🏎", "🚓", "🚑", "🚒", "🚐", "🛻", "🚚", "🚛", "🚜", "🏍", "🚲", "🚁", "✈️", "🛵", "🚀", "🛶", "🛸", "⛵️", "🚅"]
            themeName = "Cars"
            colorCard = .red
        case .animal:
            choiseTheme = ["🐣", "🙉", "🙊", "🙈", "🐵", "🐽", "🐸", "🦊", "🐨", "🐹", "🐰", "🐻", "🐼", "🐻‍❄️", "🐶", "🐱", "🐮"]
            themeName = "Animals"
            colorCard = .gray
        case .item:
            choiseTheme = ["💻", "⌚️", "📱", "⌨️", "🖥", "🖨", "🖲", "🕹", "🎥", "📷", "☎️", "📺", "⏰", "🎛", "📟", "📡", "🧯"]
            themeName = "Items"
            colorCard = .purple
        case .food:
            choiseTheme = ["🍎", "🍏", "🍊", "🍐", "🍋", "🍌", "🥭", "🍒", "🍆", "🍑", "🍓", "🫐", "🫒", "🧀", "🍟", "🍕", "🥙"]
            themeName = "Food"
            colorCard = .yellow
        case .face:
            choiseTheme = ["😀", "🥳", "😋", "😗", "🥰", "😍", "😛", "😌", "😡", "🤯", "🤬", "🥵", "😫", "🧐", "☺️", "😃", "😄", "😁"]
            themeName = "Face"
            colorCard = .green
        }
    }
    
    func refreshTheme() {
        let randomTheme = ChoiseTheme.allCases.randomElement()!
        theme(for: randomTheme)
    }
}

2. 给EmojiMemoryGame增加新游戏重置逻辑

让视图模型持有主题实例,新增newGame()方法统一处理主题刷新、卡片重建逻辑,@Published标记的模型更新后会自动触发视图刷新:

import SwiftUI

class EmojiMemoryGame: ObservableObject {
    private var theme: MemoryGameTheme
    
    init(theme: MemoryGameTheme) {
        self.theme = theme
        self.model = EmojiMemoryGame.createMemoryGame(with: theme)
    }
    
    static func createMemoryGame(with theme: MemoryGameTheme) -> MemoryGame<String> {
        return MemoryGame<String>(numberOfPairOfCards: theme.choiseTheme.count) { pairIndex in
            theme.choiseTheme[pairIndex]
        }
    }
    
    @Published private var model: MemoryGame<String>
    
    var cards: Array<MemoryGame<String>.Card> {
        model.cards
    }
    
    // 新游戏重置逻辑
    func newGame() {
        theme.refreshTheme()
        model = EmojiMemoryGame.createMemoryGame(with: theme)
    }
    
    func choose(_ card: MemoryGame<String>.Card) {
        model.choose(card)
    }
    
    // 暴露主题属性给视图使用
    var currentThemeName: String {
        theme.themeName
    }
    
    var currentThemeColor: Color {
        theme.colorCard
    }
}

3. 修改ContentView绑定逻辑

用状态包装器正确持有可观察对象,删除不存在的方法调用,卡片颜色适配当前主题:

struct ContentView: View {
    @StateObject private var viewModel: EmojiMemoryGame
    @StateObject private var themeModel: MemoryGameTheme
    
    init() {
        let theme = MemoryGameTheme()
        _themeModel = StateObject(wrappedValue: theme)
        _viewModel = StateObject(wrappedValue: EmojiMemoryGame(theme: theme))
    }
    
    var body: some View {
        VStack {
            ScrollView {
                LazyVGrid(columns: [GridItem(.adaptive(minimum: 75))]) {
                    ForEach (viewModel.cards) { card in
                        CardView(card: card, cardColor: viewModel.currentThemeColor)
                            .aspectRatio(2/3, contentMode: .fit)
                            .onTapGesture {
                                viewModel.choose(card)
                            }
                    }
                }
            }
            .foregroundColor(viewModel.currentThemeColor)
            Spacer()
            HStack {
                newGame
                Spacer()
                nameTheme
            }
        }
        .padding(.horizontal)
    }
    
    var newGame: some View {
        Button(action: {
            viewModel.newGame()
        }, label: {
            Text("New Game")
                .font(.title)
                .fontWeight(.heavy)
        })
    }
    var nameTheme: some View {
        Text(viewModel.currentThemeName)
            .font(.title3)
            .fontWeight(.heavy)
    }
}

struct CardView: View {
    let card: MemoryGame<String>.Card
    let cardColor: Color
    var body: some View {
        ZStack {
            let shape = RoundedRectangle(cornerRadius: 20)
            if card.isFaceUp {
                shape.fill().foregroundColor(.white)
                shape.strokeBorder(lineWidth: 3)
                Text(card.content).font(.largeTitle)
            } else if card.isMatched {
                shape.opacity(0)
            } else {
                shape.fill().foregroundColor(cardColor)
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
            .preferredColorScheme(.dark)
        ContentView()
            .preferredColorScheme(.light)
    }
}

修改完成后点击New Game按钮,会随机切换主题、重新洗牌生成新的卡片组,主题名称和卡片颜色也会同步更新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 22:36:24