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

SwiftUI视图切换异常:重复跳转致视图堆叠下移

问题分析与解决方案

核心问题

你当前的按钮实现逻辑完全错误:Button的action闭包里直接创建destinationView实例,但这并不会触发导航跳转,而是相当于在当前视图层级里叠加新视图。当点击指向LoggedMainView的按钮时,新的LoggedMainView会包含BottomMenu,再次点击又会叠加一层,无限嵌套导致视图不断下移。

修复步骤

1. 统一导航状态管理

用NavigationPath和ObservableObject管理导航,避免重复跳转和嵌套:

首先定义页面枚举,方便识别不同页面:

enum AppPage: Hashable {
    case loggedMain
    case search
    case profile
}

更新MainViewModel,添加导航路径属性:

class MainViewModel: ObservableObject {
    @Published var navigationPath = NavigationPath()
    // 保留你原有的业务逻辑代码
}

2. 重构按钮组件

把BtnMenu改成基于NavigationLink的导航按钮,同时添加重复跳转判断:

struct BtnMenu: View {
    @ObservedObject var logManager: MainViewModel
    var btnText: String
    var btnIcon: String
    var targetPage: AppPage
    
    var body: some View {
        NavigationLink(value: targetPage) {
            Text("\(Image(systemName: btnIcon)) \(btnText)")
        }
        .onTapGesture {
            switch targetPage {
            case .loggedMain:
                // 点击首页按钮时直接回到根视图,避免嵌套
                logManager.navigationPath.removeAll()
            default:
                // 非首页按钮,检查是否已经在目标页面,避免重复跳转
                guard let lastPage = logManager.navigationPath.last as? AppPage, lastPage != targetPage else {
                    return
                }
                logManager.navigationPath.append(targetPage)
            }
        }
    }
}

3. 修改底部菜单

传递共享的MainViewModel实例,避免每个组件新建独立实例:

struct BottomMenu: View {
    @ObservedObject var logManager: MainViewModel
    
    var body: some View {
        HStack {
            Spacer()
            BtnMenu(logManager: logManager, btnText: "Dodaj", btnIcon: "plus.app.fill", targetPage: .loggedMain)
            Spacer()
            BtnMenu(logManager: logManager, btnText: "Szukaj", btnIcon: "magnifyingglass", targetPage: .search)
            Spacer()
            BtnMenu(logManager: logManager, btnText: "Profil", btnIcon: "person.crop.circle.fill", targetPage: .profile)
            Spacer()
        }
        .padding(.bottom, 30)
        .font(.system(size: 20))
    }
}

4. 更新根视图配置

在LoggedMainView中使用NavigationStack关联导航路径,并将底部菜单放在工具栏:

struct LoggedMainView: View {
    @StateObject private var logManager = MainViewModel()
    
    var body: some View {
        NavigationStack(path: $logManager.navigationPath) {
            // 这里放你的首页内容
            Text("首页内容")
                .navigationDestination(for: AppPage.self) { page in
                    switch page {
                    case .search:
                        SearchView()
                            .toolbar {
                                ToolbarItem(placement: .bottomBar) {
                                    BottomMenu(logManager: logManager)
                                }
                            }
                    case .profile:
                        ProfileView()
                            .toolbar {
                                ToolbarItem(placement: .bottomBar) {
                                    BottomMenu(logManager: logManager)
                                }
                            }
                    case .loggedMain:
                        // 这里不会触发,因为点击首页按钮直接清空路径回到根
                        EmptyView()
                    }
                }
                .toolbar {
                    ToolbarItem(placement: .bottomBar) {
                        BottomMenu(logManager: logManager)
                    }
                }
        }
    }
}

关键说明

  • 所有页面共享同一个MainViewModel实例,保证导航状态一致
  • 点击首页按钮时直接清空导航路径回到根视图,彻底避免嵌套
  • 非首页按钮会检查当前页面,防止重复跳转相同视图

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 01:52:07