// // SettingsView.swift // punchnet // // Created by 安礼成 on 2026/1/16. // import SwiftUI struct SettingsView: View { @State private var columnVisibility: NavigationSplitViewVisibility = .all @State private var state = SettingsState() @State private var selectedMenu: MenuItem = .accout enum MenuItem: String, CaseIterable { case accout = "账号" case network = "网络" case device = "设备" case system = "软件" case about = "关于" // 图标信息 var icon: String { switch self { case .accout: return "person.crop.circle.fill" case .network: return "network" case .device: return "laptopcomputer" case .system: return "gearshape.fill" case .about: return "info.circle.fill" } } } var body: some View { NavigationSplitView(columnVisibility: $columnVisibility) { // MARK: - 自定义侧边栏 VStack(alignment: .leading, spacing: 20) { Text("设置") .font(.system(size: 24, weight: .bold)) .padding(.horizontal, 16) .padding(.top, 24) VStack(spacing: 4) { ForEach(MenuItem.allCases, id: \.self) { menu in SidebarItem( icon: menu.icon, title: menu.rawValue, isSelected: selectedMenu == menu ) .onTapGesture { // 使用精调的 spring 动画切换 withAnimation(.spring(response: 0.35, dampingFraction: 0.8)) { self.selectedMenu = menu } } } Spacer() } .padding(.horizontal, 12) } .background(VisualEffectView(material: .sidebar, blendingMode: .behindWindow)) .navigationSplitViewColumnWidth(min: 180, ideal: 200, max: 250) } detail: { // MARK: - 详情页转场 ZStack(alignment: .topLeading) { // 背景保持统一 VisualEffectView(material: .hudWindow, blendingMode: .behindWindow) .ignoresSafeArea() VStack(alignment: .leading, spacing: 0) { Group { // 使用 ID 辅助 SwiftUI 识别视图切换,触发 transition switch self.selectedMenu { case .accout: SettingsAccountView(state: self.state) case .network: SettingsNetworkView(state: self.state) case .device: SettingsDeviceView() case .system: SettingsSystemView() case .about: SettingsAboutView() } } .id(selectedMenu) // 关键:确保切换时触发转场 .transition(.asymmetric( insertion: .move(edge: .bottom).combined(with: .opacity), removal: .opacity )) Spacer() } .padding(32) // 加大留白,显得更高级 .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) } } } } // MARK: - 子组件:侧边栏按钮样式 struct SidebarItem: View { let icon: String let title: String let isSelected: Bool @State private var isHovering = false var body: some View { HStack(spacing: 12) { Image(systemName: icon) .font(.system(size: 14, weight: .medium)) .frame(width: 20) Text(title) .font(.system(size: 14, weight: .medium)) Spacer() } .padding(.horizontal, 12) .padding(.vertical, 8) .foregroundColor(isSelected ? .white : .primary.opacity(0.8)) .background { if isSelected { RoundedRectangle(cornerRadius: 8, style: .continuous) .fill(Color.blue.gradient) // 保持一致的蓝色渐变 } else if isHovering { RoundedRectangle(cornerRadius: 8, style: .continuous) .fill(Color.primary.opacity(0.05)) } } .onHover { isHovering = $0 } .contentShape(Rectangle()) } } #Preview { SettingsView() }