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

SwiftUI中@Published值变化时实现VStack淡入淡出切换

实现VStack淡入淡出切换效果

要解决NavigationStack推入时的视图突兀切换问题,同时实现淡出后淡入的动画,你可以通过ZStack分层控制透明度或者transition过渡动画来实现,核心是手动控制动画时机,避开导航切换的动画周期。

方案1:ZStack分层控制透明度(推荐)

通过将两个VStack叠加,分别控制它们的透明度和动画延迟,实现先淡出旧视图、再淡入新视图的顺序效果:

@EnvironmentObject var subscriptionManager: SubscriptionManager
// 用独立状态变量控制显示,避免直接依赖外部状态导致的突兀切换
@State private var showProductView = false

var body: some View {
    ZStack {
        // 默认显示的VStack 2
        VStack {
            Text("无产品状态内容")
            // 你的其他内容
        }
        .opacity(showProductView ? 0 : 1)
        // 淡出动画,时长0.3秒
        .animation(.easeOut(duration: 0.3), value: showProductView)
        
        // 有产品时显示的VStack 1
        VStack {
            Text("已加载产品内容")
            // 你的其他内容
        }
        .opacity(showProductView ? 1 : 0)
        // 淡入动画,延迟0.3秒等待VStack2淡出,时长0.3秒
        .animation(.easeIn(duration: 0.3).delay(0.3), value: showProductView)
    }
    .onAppear {
        // 推入视图时,如果产品已加载,延迟触发动画,避开导航的滑动动画
        if subscriptionManager.subscriptionProduct != nil {
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
                withAnimation {
                    showProductView = true
                }
            }
        }
    }
    .onChange(of: subscriptionManager.subscriptionProduct) { newProduct in
        // 产品状态变更时,触发动画切换
        withAnimation {
            showProductView = newProduct != nil
        }
    }
}

方案2:Transition过渡动画

利用SwiftUI的transition修饰符,配合状态变量的动画切换,实现视图的淡入淡出:

@EnvironmentObject var subscriptionManager: SubscriptionManager
@State private var showProductView = false

var body: some View {
    VStack {
        if showProductView {
            VStack {
                Text("已加载产品内容")
                // 你的其他内容
            }
            // VStack1淡入过渡
            .transition(.opacity.animation(.easeIn(duration: 0.3)))
        } else {
            VStack {
                Text("无产品状态内容")
                // 你的其他内容
            }
            // VStack2淡出过渡
            .transition(.opacity.animation(.easeOut(duration: 0.3)))
        }
    }
    .onAppear {
        // 延迟触发动画,避免和导航推入动画冲突
        if subscriptionManager.subscriptionProduct != nil {
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
                showProductView = true
            }
        }
    }
    .onChange(of: subscriptionManager.subscriptionProduct) { newProduct in
        withAnimation {
            showProductView = newProduct != nil
        }
    }
}

关键说明

  1. 独立状态变量:用@State private var showProductView控制显示,而非直接依赖subscriptionManager.subscriptionProduct,这样能手动控制动画触发时机。
  2. 延迟动画:onAppear里的延迟是为了避开NavigationStack的推入滑动动画,防止两个动画叠加导致的突兀切换。
  3. 顺序动画:通过delay让VStack1的淡入动画在VStack2淡出后开始,实现连贯的切换效果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 14:33:30