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

SwiftUI中如何实现交易成功页面的淡入动画?

问题:SwiftUI中交易成功页面无法实现淡入动画效果

我是iOS开发新手,正在使用SwiftUI开发股票交易项目。项目里有一个用于买卖股票的sheet,交易成功后需显示带成功消息的绿色页面,但目前该页面是突然出现的,无法实现淡入动画效果。

  • 当前效果:交易成功页面无淡入动画,直接突然显示
  • 期望效果:交易成功页面平滑淡入显示

以下是sheet的代码:

//
//  TradingSheetView.swift
//  Stock Search
//
//  Created by Kishan  on 4/29/24.
//

import SwiftUI
import SimpleToast

struct TradingSheetView: View {
    
    @EnvironmentObject var root: ToastViewModel
    @StateObject var viewModel = TradingSheetViewModel()
    
    @Binding var isTrading: Bool
    @Binding var company: Company?
    @Binding var portfolio: Portfolio?
    @Binding var wallet: Wallet?
    
    private var tradingQuantity: Int {
        let tradingQuantityInt = Int(viewModel.tradingQuantity)
        //      if tradingQuantityInt == nil {
        //          root.showToast(saying: "Please enter a valid amount")
        //      }
        return tradingQuantityInt ?? 0
    }
    
    private var tradingAmount: Double {
        return (viewModel.quote?.c ?? 0) * Double(tradingQuantity)
    }
    
    var body: some View {
        ZStack {
            VStack {
                HStack {
                    Spacer()
                    Button {
                        isTrading.toggle()
                    } label: {
                        Image(systemName: "xmark")
                            .foregroundStyle(Color(.label))
                    }
                }
                
                Text("Trade \(company?.name ?? "") shares")
                    .bold()
                
                Spacer()
                
                HStack {
                    TextField("0",
                                        text: $viewModel.tradingQuantity)
                    .font(.system(size: 100, weight: .light))
                    .keyboardType(.numberPad)
                    
                    Text(tradingQuantity > 1 ? "Shares" : "Share")
                        .font(.largeTitle)
                        .offset(y: 20)
                }
                
                HStack {
                    Spacer()
                    
                    Text("x $\((viewModel.quote?.c ?? 0).getTwoPointsString())/share = $\(tradingAmount.getTwoPointsString())")
                }
                
                Spacer()
                
                Text("$\((wallet?.amount ?? 0).getTwoPointsString()) available to buy \(company?.ticker ?? "")")
                    .font(.caption)
                    .foregroundStyle(.secondary)
                    .padding()
                
                HStack(spacing: 20) {
                    Button {
                        Task {
                            if tradingAmount > (wallet?.amount ?? 0) {
                                root.showToast(saying: "Not enough money to buy")
                                return
                            }
                            if tradingQuantity <= 0 {
                                root.showToast(saying: "Cannot buy non-positive shares")
                                return
                            }
                            await viewModel.buy(tradingQuantity,
                                                                    of: company?.ticker,
                                                                    at: viewModel.quote?.c,
                                                                    called: company?.name)
                        }
                    } label: {
                        PortfolioDetailsButton(title: "Buy")
                    }
                    Button {
                        Task {
                            if tradingQuantity > (portfolio?.quantity ?? 0) {
                                root.showToast(saying: "Not enough shares to sell")
                                return
                            }
                            if tradingQuantity <= 0 {
                                root.showToast(saying: "Cannot sell non-positive shares")
                                return
                            }
                            await viewModel.sell(tradingQuantity,
                                                                     of: company?.ticker,
                                                                     at: viewModel.quote?.c)
                        }
                    } label: {
                        PortfolioDetailsButton(title: "Sell")
                    }
                }
            }
            .padding()
            .onAppear() {
                Task {
                    await viewModel.fetchCurrentQuote(for: company?.ticker ?? "")
                }
            }
            
            if viewModel.transactionSuccess {
                withAnimation(.easeInOut.speed(5)) {
                    ZStack {
                        Color.green.ignoresSafeArea()
                        
                        VStack() {
                            Spacer()
                            
                            Text("Congratulations!")
                                .bold()
                                .font(.largeTitle)
                                .foregroundStyle(.white)
                            
                            Text(viewModel.transactionMessage)
                                .font(.callout)
                                .foregroundStyle(.white)
                                .padding(.vertical, 1)
                            
                            Spacer()
                            
                            Button {
                                isTrading.toggle()
                            } label: {
                                Text("Done")
                                    .bold()
                                    .frame(width: 350, height: 50)
                                    .background(in: .capsule)
                                    .foregroundStyle(.green)
                            }
                        }
                        .padding()
                    }
                }
            }
        }
        .simpleToast(isPresented: $root.isToastVisible,
                 options: root.toastOptions) {
            ToastView(message: $root.toastMessage)
        }
    }
}

#Preview {
    TradingSheetView(isTrading: .constant(true),
                                     company: .constant(mockCompany),
                                     portfolio: .constant(mockPortfolio),
                                     wallet: .constant(mockWallet))
}

编辑补充:按照建议尝试复现视图,代码如下:

//
//  TestView.swift
//  Stock Search
//
//  Created by Kishan  on 4/29/24.
//

import SwiftUI

struct TestView: View {
    
    @State var success = false
    
    var body: some View {
        ZStack {
            
            Button("Press here to perform transaction") {
                Task {
                    await performTransaction()
                }
            }
            
            if success {
                ZStack {
                    Color.green.ignoresSafeArea()
                    
                    VStack {
                        Text("Congratulations!")
                            .bold()
                            .font(.title)
                            .foregroundStyle(.white)
                            .padding(.vertical)
                        
                        Button {
                            Task {
                                await performTransaction()
                            }
                        } label: {
                            Text("Done")
                                .bold()
                                .frame(width: 300, height: 50)
                                .background(in: .capsule)
                                .foregroundStyle(.green)
                        }
                    }
                }
            }
        }
    }
    
    func performTransaction() async {
        // Perform some transaction
        success.toggle()
    }
}

#Preview {
    TestView()
}

我已经尝试使用.animation修饰符和withAnimation,但动画仍不生效,是否存在影响动画执行的冲突因素?


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 23:53:24