修复 Tab 导航栈路径绑定,确保子页面 push 后立即响应。

直接观察 RouterPath 并绑定 NavigationStack,移除未使用的 AppTab/AppRouter 辅助 API。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-29 11:45:34 +08:00
parent 8e34a45d50
commit d310d26293
5 changed files with 24 additions and 32 deletions

View File

@ -29,19 +29,6 @@ enum AppTab: String, CaseIterable, Identifiable, Hashable {
} }
} }
var systemImage: String {
switch self {
case .home:
"house"
case .orders:
"doc.text"
case .statistics:
"chart.bar"
case .profile:
"person"
}
}
/// Tab 使 /// Tab 使
var selectedImageName: String { var selectedImageName: String {
switch self { switch self {
@ -83,9 +70,4 @@ enum AppTab: String, CaseIterable, Identifiable, Hashable {
ProfileRootView() ProfileRootView()
} }
} }
@ViewBuilder
var label: some View {
Label(title, systemImage: systemImage)
}
} }

View File

@ -100,16 +100,6 @@ final class AppRouter: ObservableObject {
return router return router
} }
/// SwiftUI NavigationStack 使
func binding(for tab: AppTab) -> Binding<[AppRoute]> {
let router = router(for: tab)
return Binding(
get: { router.path },
set: { router.path = $0 }
)
}
/// Tab /// Tab
func select(_ tab: AppTab) { func select(_ tab: AppTab) {
selectedTab = tab selectedTab = tab

View File

@ -28,8 +28,8 @@ Main 模块负责登录后的主界面 Tab 容器,以及当前尚未迁移页
2. `TabView` 使用内部 `MainTabSelection` 作为选择值,普通 Tab 映射到 `AppTab`,扫码映射到 `.scanner` 2. `TabView` 使用内部 `MainTabSelection` 作为选择值,普通 Tab 映射到 `AppTab`,扫码映射到 `.scanner`
3. 普通 Tab 切换时调用 `AppRouter.select(_:)` 更新当前业务 Tab。 3. 普通 Tab 切换时调用 `AppRouter.select(_:)` 更新当前业务 Tab。
4. 每个普通 Tab 通过 `TabNavigationStackHost` 创建自己的 `NavigationStack(path:)` 4. 每个普通 Tab 通过 `TabNavigationStackHost` 创建自己的 `NavigationStack(path:)`
5. 路径绑定来自 `appRouter.binding(for:)` 5. 导航栈宿主直接观察当前 Tab 对应的 `RouterPath`,并把 `$router.path` 绑定给 `NavigationStack`
6. Tab 内页面需要进入尚未迁移的子页面时,通过当前 Tab 注入的 `RouterPath` push 一个 `AppRoute.placeholder` 6. Tab 内页面需要进入子页面时,通过当前 Tab 注入的 `RouterPath` push 对应 `AppRoute`
7. `navigationDestination` 根据 `AppRoute` 展示详情页。 7. `navigationDestination` 根据 `AppRoute` 展示详情页。
8. 子页面展示时读取 `AppRoute.hidesTabBarWhenPushed`,默认隐藏底部 TabBar。 8. 子页面展示时读取 `AppRoute.hidesTabBarWhenPushed`,默认隐藏底部 TabBar。

View File

@ -141,7 +141,17 @@ private struct TabNavigationStackHost: View {
let tab: AppTab let tab: AppTab
var body: some View { var body: some View {
NavigationStack(path: appRouter.binding(for: tab)) { TabNavigationStackContent(tab: tab, router: appRouter.router(for: tab))
}
}
/// Tab RouterPath
private struct TabNavigationStackContent: View {
let tab: AppTab
@ObservedObject var router: RouterPath
var body: some View {
NavigationStack(path: $router.path) {
tab.rootView tab.rootView
.navigationTitle(tab.title) .navigationTitle(tab.title)
.navigationDestination(for: AppRoute.self) { route in .navigationDestination(for: AppRoute.self) { route in
@ -149,7 +159,7 @@ private struct TabNavigationStackHost: View {
.toolbar(route.hidesTabBarWhenPushed ? .hidden : .visible, for: .tabBar) .toolbar(route.hidesTabBarWhenPushed ? .hidden : .visible, for: .tabBar)
} }
} }
.environmentObject(appRouter.router(for: tab)) .environmentObject(router)
} }
} }

View File

@ -64,6 +64,16 @@ final class NavigationRouterTests: XCTestCase {
XCTAssertNil(router.pendingOrderScanCode) XCTAssertNil(router.pendingOrderScanCode)
} }
/// Tab
func testProfileSettingsRouteCanBePushedIntoProfileTabPath() {
let appRouter = AppRouter()
let profileRouter = appRouter.router(for: .profile)
profileRouter.navigate(to: .profile(.settings))
XCTAssertEqual(profileRouter.path.last, .profile(.settings))
}
/// ///
func testOrderRoutesCanBePushedIntoRouterPath() throws { func testOrderRoutesCanBePushedIntoRouterPath() throws {
let router = RouterPath() let router = RouterPath()