import SwiftUI enum TjTab: String, Hashable, CaseIterable { case home, trend, me var label: String { switch self { case .home: return "首页" case .trend: return "趋势" case .me: return "我的" } } var icon: String { switch self { case .home: return "house" case .trend: return "chart.line.uptrend.xyaxis" case .me: return "person.circle" } } } enum ActiveFlow: Identifiable { case quick, archive var id: String { String(describing: self) } } struct RootView: View { @State private var tab: TjTab = .home @State private var showRecordSheet = false @State private var activeFlow: ActiveFlow? var body: some View { VStack(spacing: 0) { Group { switch tab { case .home: HomeView(onTapArchive: {}) case .trend: TrendsView() case .me: MeView() } } .frame(maxWidth: .infinity, maxHeight: .infinity) TabBar(active: tab, onTap: { tab = $0 }, onTapRecord: { showRecordSheet = true }) } .background(Tj.Palette.sand.ignoresSafeArea()) .sheet(isPresented: $showRecordSheet) { RecordSheet { kind in showRecordSheet = false DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { switch kind { case .quick: activeFlow = .quick case .archive: activeFlow = .archive case .diary: break } } } } #if os(iOS) .fullScreenCover(item: $activeFlow) { flow in switch flow { case .quick: QuickCaptureFlow(onClose: { activeFlow = nil }) case .archive: ArchiveFlow(onClose: { activeFlow = nil }) } } #else .sheet(item: $activeFlow) { flow in switch flow { case .quick: QuickCaptureFlow(onClose: { activeFlow = nil }) case .archive: ArchiveFlow(onClose: { activeFlow = nil }) } } #endif } } private struct TabBar: View { let active: TjTab let onTap: (TjTab) -> Void let onTapRecord: () -> Void var body: some View { HStack(spacing: 0) { tabItem(.home) Color.clear.frame(width: 60, height: 1) tabItem(.trend) tabItem(.me) } .padding(.horizontal, 12) .padding(.top, 10) .padding(.bottom, 4) .background( Tj.Palette.paper .overlay(alignment: .top) { Rectangle() .fill(Tj.Palette.lineSoft) .frame(height: 1) } ) .overlay(alignment: .top) { recordButton.offset(y: -22) } } private func tabItem(_ t: TjTab) -> some View { Button { onTap(t) } label: { VStack(spacing: 4) { Image(systemName: t.icon) .font(.system(size: 20, weight: .regular)) .frame(width: 26, height: 26) Text(t.label) .font(.system(size: 11)) } .foregroundStyle(active == t ? Tj.Palette.ink : Tj.Palette.text3) .frame(maxWidth: .infinity) .padding(.vertical, 4) .contentShape(Rectangle()) } .buttonStyle(.plain) } private var recordButton: some View { Button(action: onTapRecord) { VStack(spacing: 4) { ZStack { Circle() .fill(Tj.Palette.ink) .shadow(color: Color(red: 0.157, green: 0.216, blue: 0.176).opacity(0.25), radius: 12, x: 0, y: 4) Image(systemName: "plus") .font(.system(size: 20, weight: .semibold)) .foregroundStyle(Tj.Palette.paper) } .frame(width: 52, height: 52) Text("记录") .font(.system(size: 11)) .foregroundStyle(Tj.Palette.ink) } } .buttonStyle(.plain) } } #Preview { RootView() }