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

SwiftUI实现单视图内点击按钮切换锻炼内容,避免计时器异常

单视图内切换健身内容,解决Timer重复调用导致的倒计时异常问题

问题背景

原本通过NavigationPath跳转多视图展示不同锻炼内容,但这种方式会创建多个TimerView实例,导致计时器被多次调用,出现倒计时速度异常加快的问题。现在需要实现在单个视图内通过按钮切换锻炼的标题、视频示例和步骤文本。

修改后的完整代码

import SwiftUI
import AVKit

// 假设你的数据结构定义如下(如果已存在可忽略):
// struct Exercise {
//     let title: String
//     let video: AVPlayer
//     let steps: String
// }
// struct ExercisePlan {
//     let exercises: [Exercise]
// }

struct ExerciseScreenView: View {
    @Binding var streaks: Streaks
    @Binding var timerStruct: TimerStruct
    private let defaultCountdown = 300
    @State private var currentExerciseIndex = 0
    let exercisePlan: ExercisePlan
    @Binding var navigationPath: NavigationPath
    
    private func resetTimer() {
        timerStruct.countdownTimer = defaultCountdown
        timerStruct.timerRunning = false
    }
    
    private func switchToNextExercise() {
        if currentExerciseIndex < exercisePlan.exercises.count - 1 {
            currentExerciseIndex += 1
            resetTimer()
        } else {
            // 所有锻炼完成后返回上一页,可按需修改逻辑
            navigationPath.removeLast()
        }
    }
    
    var body: some View {
        VStack {
            Form {
                Section(header: Text("\(currentExerciseIndex + 1)th Exercise (Scroll down for steps)")) {
                    Text(exercisePlan.exercises[currentExerciseIndex].title)
                        .font(.system(size: 35, weight: .medium))
                }
                
                Section(header: Text("Video Example")) {
                    VideoPlayer(player: exercisePlan.exercises[currentExerciseIndex].video)
                        .scaledToFit()
                        .frame(alignment: .center)
                        .cornerRadius(10)
                }
                
                Section(header: Text("Steps:")) {
                    Text(exercisePlan.exercises[currentExerciseIndex].steps)
                        .font(.system(size: 20, weight: .regular))
                        .padding()
                        .frame(alignment: .center)
                }
            }
            
            TimerView(streaks: $streaks, timerStruct: $timerStruct)
                .padding(.bottom, 15)
            
            Button(action: switchToNextExercise) {
                Text(currentExerciseIndex < exercisePlan.exercises.count - 1 ? "Next Exercise" : "Finish")
                    .padding()
                    .background(Color(red: 184/255, green: 243/255, blue: 255/255))
                    .foregroundColor(.black)
                    .cornerRadius(10)
            }
            .padding(.horizontal, 10)
            .padding(.bottom, 10)
            .navigationBarBackButtonHidden()
        }
    }
}

核心修改说明

  • 用索引控制内容切换:新增currentExerciseIndex状态变量,通过它动态展示当前锻炼的标题、视频和步骤,彻底避免多视图跳转带来的Timer实例重复问题。
  • 切换时重置计时器:每次切换锻炼时调用resetTimer(),将计时器重置为初始值并停止运行,防止多个计时逻辑叠加导致倒计时过快。
  • 动态按钮文本:根据当前是否为最后一个锻炼,自动切换按钮文本为"Next Exercise"或"Finish",提升用户体验。
  • 数据适配:假设ExercisePlan包含一个exercises数组,如果你的原数据结构不同,只需对应调整数组访问的部分即可。

这样修改后,所有锻炼内容都在同一个视图内渲染,不会重复创建Timer相关实例,完美解决倒计时异常的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 20:05:23