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

SwiftUI条件视图(网格/列表)切换的动画实现方案咨询

网格与列表切换的过渡动画实现方案

你当前的代码里,直接用if/else切换ScrollView和List,再加上Group的包裹,导致SwiftUI没法正确识别并应用过渡动画。以下是具体的修复步骤:

核心修改点

  • 用ZStack替代Group包裹两个视图,让网格和列表处于同一层级,为过渡动画提供基础
  • 给网格和列表视图分别添加.transition()定义动画效果
  • 在切换状态的代码外层包裹withAnimation,触发状态变化时的动画

修改后的完整代码

struct FrameworkGridView: View {
    @StateObject var viewModel = FrameworkGridViewModel()
    @Binding var isGrid: Bool
    var body: some View {
        NavigationView {
            ZStack { // 替换原来的Group为ZStack
                if viewModel.isGrid {
                    ScrollView {
                        LazyVGrid(columns: viewModel.columns) {
                            ForEach(MockData.frameworks) { framework in
                                FrameworkTitleView(framework: framework, isGrid: $viewModel.isGrid)
                                    .onTapGesture {
                                        viewModel.selectedFramework = framework
                                    }
                            }
                        }
                    }
                    .sheet(isPresented: $viewModel.isShowingDetailView) {
                        DetailView(framework: viewModel.selectedFramework ?? MockData.sampleFramework, isShowingDetailView: $viewModel.isShowingDetailView, isGrid: $viewModel.isGrid)
                    }
                    .transition(.scale.combined(with: .opacity)) // 添加过渡效果
                    .zIndex(1) // 确保当前显示的视图在顶层
                } else {
                    List {
                        ForEach(MockData.frameworks) { framework in
                            NavigationLink(destination: DetailView(framework: framework, isShowingDetailView: $viewModel.isShowingDetailView, isGrid: $viewModel.isGrid)) {       
                                FrameworkTitleView(framework: framework, isGrid: $viewModel.isGrid)
                            }
                        }
                    }
                    .transition(.scale.combined(with: .opacity)) // 添加过渡效果
                    .zIndex(1) // 确保当前显示的视图在顶层
                }
            }
            .toolbar {
                Button {
                    withAnimation { // 包裹状态切换代码
                        viewModel.isGrid.toggle()
                    }
                } label: {
                    Image(systemName: viewModel.isGrid ? "list.dash" : "square.grid.2x2")
                }
            }
        }
    }
}

额外说明

  • 你可以自定义过渡效果,比如把.scale.combined(with: .opacity)换成.slide、.move(edge: .leading)等,或者组合多种过渡
  • 添加.zIndex(1)是为了避免两个视图在切换时出现层级混乱,确保当前显示的视图始终在最上层
  • 如果你的FrameworkTitleView本身有布局差异,也可以给它添加动画,让单个Item的切换更流畅

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 21:39:19