SwiftUI实现iPad Pro应用侧滑飞入动画方案咨询
实现SwiftUI版iPad Pro解锁式飞入动画
要实现类似iPad Pro解锁时应用从右侧依次飞入的效果,核心是利用偏移+透明度动画,配合逐元素延迟打造依次入场的节奏。下面针对你的DashboardView给出具体修改方案:
步骤1:移除TabView,改用直观布局容器
删掉原代码中的TabView,改用ScrollView嵌套VStack(或Grid,按需调整)展示所有卡片按钮,无需左右滑动即可直接点击操作。
步骤2:添加入场动画逻辑
给每个卡片设置初始状态(偏移至屏幕右侧+完全透明),在视图加载完成后,通过带递增延迟的动画让卡片依次从右侧飞入并显现。
修改后的完整代码
struct DashboardView: View { @EnvironmentObject var dashboardModel: DashboardModel @EnvironmentObject var gameModel: GameModel @Binding var isConnected: Bool // 控制动画触发状态,初始为未激活 @State private var isAnimated = false var body: some View { NavigationView { ZStack { LinearGradient(gradient: Gradient(colors: [.black, .gray, .black]), startPoint: .topLeading, endPoint: .bottomTrailing) ScrollView { VStack(spacing: 20) { // 遍历卡片数据,为每个卡片绑定动画 ForEach(Array(dashboardModel.cards.enumerated()), id: \.element.id) { index, card in NavigationLink(destination: getDestination(for: index)) { CardView(data: card) } .isDetailLink(false) // 初始状态:偏移至屏幕右侧+完全透明 .offset(x: isAnimated ? 0 : UIScreen.main.bounds.width) .opacity(isAnimated ? 1 : 0) // 递增延迟实现依次飞入效果,可调整0.1数值改变节奏 .animation(.interpolatingSpring(stiffness: 100, damping: 15).delay(Double(index) * 0.1), value: isAnimated) } } .padding() } } .navigationTitle("Herzlich Willkommen zur Spielerfassung") .toolbar { ToolbarItem(placement: .navigationBarLeading) { Button { withAnimation(.spring()){ gameModel.currentTeam = nil gameModel.saisons = [Saison]() } } label: { Image(systemName: "house.fill") .resizable() .scaledToFit() .frame(width: 35, height: 35) } } if gameModel.offlineChangeCounter > 0 { ToolbarItem(placement: .navigationBarTrailing) { Button { if isConnected { gameModel.pushOfflineData() gameModel.offlineChangeCounter = 0 } else { gameModel.errorText = "Sorgen Sie für eine aktive Internetverbindung." gameModel.showErrorToast = true } } label: { Image(systemName: "icloud.and.arrow.up") .resizable() .scaledToFit() .foregroundColor(.white) .frame(width: 35, height: 35) } } } if !isConnected { ToolbarItem(placement: .navigationBarTrailing) { Image(systemName: "wifi.slash") .resizable() .scaledToFit() .foregroundColor(.red) .frame(width: 35, height: 35) } } } .toolbarColorScheme(.dark, for: .navigationBar) .toolbarBackground(.visible, for: .navigationBar) .ignoresSafeArea() // 视图出现时触发动画 .onAppear { isAnimated = true } } .navigationViewStyle(StackNavigationViewStyle()) .simpleToast(isPresented: $gameModel.showErrorToast, options: SimpleToastOptions(alignment: .bottom, hideAfter: 3, showBackdrop: false, animation: .easeIn, modifierType: .slide)) { gameModel.showErrorToast = false gameModel.errorText = "" } content: { ErrorToastView() .padding(.bottom, 0) } } // 统一管理卡片对应的跳转目标,替代原硬编码逻辑 private func getDestination(for index: Int) -> some View { switch index { case 0: return AnyView(PlayerView()) case 1: return AnyView(FastGamedayView()) // 取消注释即可启用 case 2: return AnyView(SaisonsView()) case 3: return AnyView(GamedayView()) case 4: return AnyView(HistoryView()) case 5: return AnyView(StatisticsView()) default: return AnyView(EmptyView()) } } }
关键细节说明
- 动画手感:使用
interpolatingSpring弹簧动画模拟系统原生弹性效果,可调整stiffness(刚度)和damping(阻尼)参数改变动画快慢和回弹幅度。 - 延迟节奏:通过
Double(index) * 0.1给每个卡片设置递增延迟,数值越小入场速度越快,可按需调整。 - 布局灵活度:如果需要网格排版,可将VStack替换为
LazyVGrid,适配不同屏幕尺寸。 - 代码整洁性:新增
getDestination方法统一管理跳转视图,避免大量硬编码的NavigationLink重复逻辑。
内容的提问来源于stack exchange,提问作者schmale96
相关产品推荐
相关产品推荐

