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

更新AppStorage状态后导航与Tab选中丢失,主题切换页面跳转问题

问题描述

我希望实现App配色方案切换功能,但在ThemeView中点击主题样式时,页面会自动退回SettingsView,且Tab会重新选中Home页。请问如何在切换配色方案后停留在ThemeView中?


相关代码

AppTabView.swift

public enum ThemeStyle: Int, CaseIterable {
   
  case automatic
  case light
  case dark
}

extension View {
   
  @ViewBuilder
  func themeStyle(_ themeStyle: ThemeStyle) -> some View {
    switch themeStyle {
    case .automatic:
      self
    case .light:
      preferredColorScheme(.light)
    case .dark:
      preferredColorScheme(.dark)
    }
  }
}

struct AppTabView: View {
   
  @AppStorage(StorageKeys.themeStyle) private var themeStyle: ThemeStyle = .automatic
   
  var body: some View {
    TabView(selection: $tabItem) {
      Text("First Tab")
        .tabItem {
          Label("Home", systemImage: .house)
        }
      NavigationView {
        SettingsView()
      }
      .tabItem {
        Label("Settings", systemImage: .gearshapeFill)
      }
    }
    .themeStyle(themeStyle)
    .toggleStyle(SwitchToggleStyle(tint: .accentColor))
  }
}

SettingsView.swift

struct SettingsView: View {
  var body: some View {
    List {
      Section {
        NavigationLink {
          ThemeView()
        } label: {
          Label("TITLE_THEME", systemImage: .circleLefthalfFill)
        }
    }
    .navigationTitle("TITLE_SETTINGS")
    .navigationBarTitleDisplayMode(.inline)
  }
}

ThemeView.swift

struct ThemeView: View {
   
  @AppStorage(StorageKeys.themeStyle) private var themeStyle: ThemeStyle = .automatic
   
  @ViewBuilder
  private func text(_ themeStyle: ThemeStyle) -> some View {
    switch themeStyle {
    case .automatic:
      Text("TITLE_THEME_AUTOMATIC")
    case .light:
      Text("TITLE_THEME_LIGHT")
    case .dark:
      Text("TITLE_THEME_DARK")
    }
  }
   
  @ViewBuilder
  private func image(_ themeStyle: ThemeStyle) -> some View {
    switch themeStyle {
    case .automatic:
      Image(systemName: .circleLefthalfFill)
    case .light:
      Image(systemName: .sunMax)
    case .dark:
      Image(systemName: .moon)
    }
  }
   
  var body: some View {
    List {
      ForEach(ThemeStyle.allCases, id: \.rawValue) { value in
        Button {
          themeStyle = value
        } label: {
          HStack {
            Label {
              text(value)
                .foregroundColor(.label)
            } icon: {
              image(value)
            }
            if themeStyle == value {
              Spacer()
              Image(systemName: .checkmark)
            }
          }
        }
      }
    }
    .navigationTitle("TITLE_THEME")
    .navigationBarTitleDisplayMode(.inline)
  }
}

解决方案

问题核心是切换主题时,AppTabView因themeStyle变化触发整体重绘,嵌套在Tab项内的NavigationView会被重新初始化,导致导航栈重置、Tab选中状态丢失。

1. 调整NavigationView层级

将NavigationView从Settings的Tab项中移出,包裹整个TabView,避免主题切换时导航栈被重置:

struct AppTabView: View {
   
  @AppStorage(StorageKeys.themeStyle) private var themeStyle: ThemeStyle = .automatic
  @State private var tabItem: Int = 1 // 初始化选中Settings页,可按需调整
   
  var body: some View {
    NavigationView {
      TabView(selection: $tabItem) {
        Text("First Tab")
          .tabItem {
            Label("Home", systemImage: .house)
          }
          .tag(0)
        SettingsView()
          .tabItem {
            Label("Settings", systemImage: .gearshapeFill)
          }
          .tag(1)
      }
      .navigationTitle(tabItem == 0 ? "Home" : "Settings")
      .navigationBarTitleDisplayMode(.inline)
    }
    .themeStyle(themeStyle)
    .toggleStyle(SwitchToggleStyle(tint: .accentColor))
  }
}

2. 移除SettingsView内的嵌套NavigationView

由于外层已有NavigationView,SettingsView无需再嵌套:

struct SettingsView: View {
  var body: some View {
    List {
      Section {
        NavigationLink {
          ThemeView()
        } label: {
          Label("TITLE_THEME", systemImage: .circleLefthalfFill)
        }
      }
    }
    .navigationTitle("TITLE_SETTINGS")
    .navigationBarTitleDisplayMode(.inline)
  }
}

3. 可选:持久化Tab选中状态

若希望重启App后保留上次选中的Tab,可将tabItem改用@AppStorage存储:

@AppStorage("selectedTab") private var tabItem: Int = 1

修改完成后,切换主题时ThemeView会保持当前页面状态,不会退回SettingsView,Tab选中状态也能稳定保留。

内容的提问来源于stack exchange,提问作者Xiaolong.Jin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 00:35:41