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

SwiftUI:点击按钮不中断动画修改NavigationLink切换颜色

解决SwiftUI中NavigationLink动画颜色切换不中断的问题

问题描述

我需要实现点击按钮时修改带有持续颜色切换动画的NavigationLink的两种颜色,且要求动画不中断。但直接修改颜色变量后,NavigationLink仅变为目标颜色之一,动画也停止了。

原代码

import SwiftUI

struct FirstView: View {
    
    @State var animate: Bool = false
    
    @State var secondaryColor: Color = Color("SecondaryAccentColor")
    @State var primaryColor: Color = Color("AccentColor")
    
    var body: some View {
        ScrollView {
            VStack(spacing: 10) {
                
                Text("Click on the Navigate button to go to the next page!")
                    .font(.title)
                    .fontWeight(.semibold)
                
                Text("Click on the Color button to change the colors!")
                    .padding(.bottom, 25)
                
                NavigationLink(
                    destination: NextPage(),
                    label: {
                        Text("NAVIGATE")
                            .foregroundColor(.white)
                            .font(.title3)
                            .fontWeight(.bold)
                            .frame(height: 60)
                            .frame(maxWidth: .infinity)
                            .background(animate ? secondaryColor : primaryColor)
                            .cornerRadius(15)
                    })
                .padding(.horizontal, 70)
                .shadow(
                    color: animate ? secondaryColor.opacity(0.4) : primaryColor.opacity(0.4),
                    radius: 15,
                    x: 0,
                    y: 30)
                
                
                Spacer()
                
                Button(action: {
                     
                    //CODE FOR THE CHANGING COLORS
                    
                })
                {
                    Text("Color")
                }
                   
            }
            .frame(maxWidth: 400)
            .multilineTextAlignment(.center)
            .padding(30)
            .onAppear(perform: addAnimation)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
    }
    
    
    func addAnimation() {
        guard !animate else { return }
        DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
            withAnimation(
            Animation
                .easeOut(duration: 0.5)
                .repeatForever()
            ) {
                animate.toggle()
            }
        }
    }
    
}

struct FirstView_Previews: PreviewProvider {
    static var previews: some View {
        NavigationView {
            FirstView()
                .navigationTitle("Hi")
        }
    }
}

尝试的无效代码

Button(action: {
                     
    primaryColor = Color.red
    secondaryColor = Color.yellow

}) {
    Text("Color")
}

执行后NavigationLink仅变为黄色,动画停止。

解决方案

问题根源在于原代码依赖布尔值animate的toggle来触发颜色切换,修改颜色变量时会导致视图重渲染,中断原有的repeatForever动画。我们可以改用自动反转的颜色插值动画,让颜色在两个目标值之间平滑过渡,修改颜色时只需更新目标值并保持动画运行。

修改后的完整代码:

import SwiftUI

struct FirstView: View {
    
    @State var primaryColor: Color = Color("AccentColor")
    @State var secondaryColor: Color = Color("SecondaryAccentColor")
    // 用于实时显示当前动画中的颜色
    @State var currentColor: Color = Color("AccentColor")
    
    var body: some View {
        ScrollView {
            VStack(spacing: 10) {
                
                Text("Click on the Navigate button to go to the next page!")
                    .font(.title)
                    .fontWeight(.semibold)
                
                Text("Click on the Color button to change the colors!")
                    .padding(.bottom, 25)
                
                NavigationLink(
                    destination: NextPage(),
                    label: {
                        Text("NAVIGATE")
                            .foregroundColor(.white)
                            .font(.title3)
                            .fontWeight(.bold)
                            .frame(height: 60)
                            .frame(maxWidth: .infinity)
                            .background(currentColor)
                            .cornerRadius(15)
                    })
                .padding(.horizontal, 70)
                .shadow(
                    color: currentColor.opacity(0.4),
                    radius: 15,
                    x: 0,
                    y: 30)
                
                
                Spacer()
                
                Button(action: {
                    // 更新颜色目标值
                    primaryColor = .red
                    secondaryColor = .yellow
                    
                    // 重新触发动画,让currentColor在新的颜色间继续过渡
                    withAnimation(Animation.easeOut(duration: 0.5).repeatForever(autoreverses: true)) {
                        currentColor = secondaryColor
                    }
                })
                {
                    Text("Color")
                }
                   
            }
            .frame(maxWidth: 400)
            .multilineTextAlignment(.center)
            .padding(30)
            .onAppear(perform: addAnimation)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
    }
    
    
    func addAnimation() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
            // 使用autoreverses让动画自动在两种颜色间来回切换
            withAnimation(Animation.easeOut(duration: 0.5).repeatForever(autoreverses: true)) {
                currentColor = secondaryColor
            }
        }
    }
    
}

struct FirstView_Previews: PreviewProvider {
    static var previews: some View {
        NavigationView {
            FirstView()
                .navigationTitle("Hi")
        }
    }
}

关键修改说明

  1. 新增currentColor状态变量,用于绑定NavigationLink的背景和阴影颜色,作为动画的实时值
  2. 动画改为使用repeatForever(autoreverses: true),让颜色在primaryColor和secondaryColor之间自动来回过渡,无需手动toggle布尔值
  3. 点击按钮修改颜色时,更新primaryColor和secondaryColor后,重新触发动画,让currentColor在新的颜色目标间继续平滑过渡,确保动画不中断

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 14:10:35