fix(ios): TabBar 隐藏改回直接 .toolbar(.hidden, for: .tabBar)
- 移除 AnimatedTabBarHide 环境值动画系统 - 所有子页面统一使用 .toolbar(.hidden, for: .tabBar) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
5faff2f5ca
commit
7f252b48f0
@ -1,48 +1,7 @@
|
||||
import SwiftUI
|
||||
|
||||
// MARK: - TabBar hide animation key
|
||||
|
||||
struct TabBarVisibleKey: EnvironmentKey {
|
||||
static let defaultValue: Binding<Bool> = .constant(false)
|
||||
}
|
||||
|
||||
extension EnvironmentValues {
|
||||
var isTabBarHidden: Binding<Bool> {
|
||||
get { self[TabBarVisibleKey.self] }
|
||||
set { self[TabBarVisibleKey.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
/// 子页面添加此 modifier 即可获得带动画的 TabBar 隐藏/出现效果
|
||||
struct AnimatedTabBarHide: ViewModifier {
|
||||
@Environment(\.isTabBarHidden) private var isTabBarHidden
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
content
|
||||
.onAppear {
|
||||
withAnimation(.easeInOut(duration: 0.28)) {
|
||||
isTabBarHidden.wrappedValue = true
|
||||
}
|
||||
}
|
||||
.onDisappear {
|
||||
withAnimation(.easeInOut(duration: 0.28)) {
|
||||
isTabBarHidden.wrappedValue = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension View {
|
||||
func animatedTabBarHide() -> some View {
|
||||
modifier(AnimatedTabBarHide())
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - ContentView
|
||||
|
||||
struct ContentView: View {
|
||||
@State private var selectedTab = "study"
|
||||
@State private var tabBarHidden = false
|
||||
|
||||
var body: some View {
|
||||
TabView(selection: $selectedTab) {
|
||||
@ -83,9 +42,6 @@ struct ContentView: View {
|
||||
.tag("profile")
|
||||
}
|
||||
.tint(Color.zxPrimary)
|
||||
.toolbar(tabBarHidden ? .hidden : .visible, for: .tabBar)
|
||||
.animation(.easeInOut(duration: 0.28), value: tabBarHidden)
|
||||
.environment(\.isTabBarHidden, $tabBarHidden)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -68,7 +68,7 @@ struct AIChatPage: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationBarTitleDisplayMode(.inline).animatedTabBarHide()
|
||||
.navigationBarTitleDisplayMode(.inline).toolbar(.hidden, for: .tabBar)
|
||||
.toolbarBackground(.hidden, for: .navigationBar)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .topBarTrailing) {
|
||||
|
||||
@ -101,7 +101,7 @@ struct AIFeedbackPageView: View {
|
||||
.transition(.opacity.combined(with: .scale(scale: 0.95)))
|
||||
}
|
||||
}
|
||||
.navigationBarTitleDisplayMode(.inline).animatedTabBarHide()
|
||||
.navigationBarTitleDisplayMode(.inline).toolbar(.hidden, for: .tabBar)
|
||||
.toolbarBackground(.hidden, for: .navigationBar)
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,7 +39,7 @@ struct ActiveRecallView: View {
|
||||
.scrollIndicators(.hidden)
|
||||
}
|
||||
}
|
||||
.navigationBarTitleDisplayMode(.inline).animatedTabBarHide()
|
||||
.navigationBarTitleDisplayMode(.inline).toolbar(.hidden, for: .tabBar)
|
||||
.toolbarBackground(.hidden, for: .navigationBar)
|
||||
.task { await viewModel.loadQuestions() }
|
||||
.overlay {
|
||||
|
||||
@ -12,6 +12,6 @@ struct DailyThinkingPage: View {
|
||||
VStack(alignment:.leading,spacing:8){Text("你的回答").font(.system(size:13,weight:.semibold)).foregroundColor(Color.zxF04);TextEditor(text:$answer).zxFontScaled(size:13).foregroundColor(Color.zxF0).tint(Color.zxPurple).frame(minHeight:160).scrollContentBackground(.hidden).padding(12).background(Color.zxFill004).clipShape(RoundedRectangle(cornerRadius:14)).overlay(RoundedRectangle(cornerRadius:14).stroke(Color.zxBorder008,lineWidth:1))}
|
||||
if !submitted{ NavigationLink(value: Route.aiFeedback){ Text("提交回答,获取 AI 反馈").font(.system(size:14,weight:.bold)).foregroundColor(.white).frame(maxWidth:.infinity).frame(height:52).background(ZXGradient.ctaPurple).clipShape(RoundedRectangle(cornerRadius:16)).shadow(color:Color(hex:"#7C6EFA",opacity:0.3),radius:24) }.zxPressable() }
|
||||
}.padding(.horizontal,20).padding(.top, 8).padding(.bottom,120) }.scrollIndicators(.hidden)
|
||||
}.navigationBarTitleDisplayMode(.inline).animatedTabBarHide().toolbarBackground(.hidden,for:.navigationBar)
|
||||
}.navigationBarTitleDisplayMode(.inline).toolbar(.hidden, for: .tabBar).toolbarBackground(.hidden,for:.navigationBar)
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,7 +32,7 @@ struct RecallTestPage: View {
|
||||
}
|
||||
.scrollIndicators(.hidden)
|
||||
}
|
||||
.navigationBarTitleDisplayMode(.inline).animatedTabBarHide()
|
||||
.navigationBarTitleDisplayMode(.inline).toolbar(.hidden, for: .tabBar)
|
||||
.toolbarBackground(.hidden, for: .navigationBar)
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ struct WeakPointsPage: View {
|
||||
}
|
||||
.scrollIndicators(.hidden)
|
||||
}
|
||||
.navigationBarTitleDisplayMode(.inline).animatedTabBarHide()
|
||||
.navigationBarTitleDisplayMode(.inline).toolbar(.hidden, for: .tabBar)
|
||||
.toolbarBackground(.hidden, for: .navigationBar)
|
||||
}
|
||||
}
|
||||
|
||||
@ -133,6 +133,6 @@ struct LibrarySearchView: View {
|
||||
}
|
||||
}.padding(.horizontal, 20) }.scrollIndicators(.hidden)
|
||||
}
|
||||
}.navigationBarTitleDisplayMode(.inline).animatedTabBarHide().toolbarBackground(.hidden, for: .navigationBar)
|
||||
}.navigationBarTitleDisplayMode(.inline).toolbar(.hidden, for: .tabBar).toolbarBackground(.hidden, for: .navigationBar)
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,7 +72,7 @@ struct CreateLibraryPage: View {
|
||||
}
|
||||
.disabled(isCreating || name.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty || desc.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty)
|
||||
}.padding(.horizontal, 20).padding(.top, 20) }.scrollIndicators(.hidden) }
|
||||
}.navigationBarTitleDisplayMode(.inline).toolbarBackground(.hidden, for: .navigationBar).animatedTabBarHide()
|
||||
}.navigationBarTitleDisplayMode(.inline).toolbarBackground(.hidden, for: .navigationBar).toolbar(.hidden, for: .tabBar)
|
||||
.photosPicker(isPresented: $showCoverPicker, selection: $coverPhotoItem, matching: .images)
|
||||
.onChange(of: coverPhotoItem) { _, item in
|
||||
guard let item else { return }
|
||||
@ -238,7 +238,7 @@ struct LibraryDetailPage: View {
|
||||
.zxPullToRefresh { await viewModel.refresh(knowledgeBaseId: knowledgeBaseId) }
|
||||
}
|
||||
}
|
||||
.navigationBarTitleDisplayMode(.inline).toolbarBackground(.hidden, for: .navigationBar).animatedTabBarHide()
|
||||
.navigationBarTitleDisplayMode(.inline).toolbarBackground(.hidden, for: .navigationBar).toolbar(.hidden, for: .tabBar)
|
||||
.onChange(of: detailTab) { _, newTab in
|
||||
if newTab == 1 && sources.isEmpty { Task { await loadSources() } }
|
||||
}
|
||||
@ -455,7 +455,7 @@ struct AddKnowledgePage: View {
|
||||
.disabled(!canSave || isSaving)
|
||||
}.padding(.horizontal, 20).padding(.top, 8).padding(.bottom, 80) }.scrollIndicators(.hidden) }
|
||||
}
|
||||
.navigationBarTitleDisplayMode(.inline).toolbarBackground(.hidden, for: .navigationBar).animatedTabBarHide()
|
||||
.navigationBarTitleDisplayMode(.inline).toolbarBackground(.hidden, for: .navigationBar).toolbar(.hidden, for: .tabBar)
|
||||
.fileImporter(isPresented: $showFilePicker, allowedContentTypes: [.plainText, .pdf, .image], allowsMultipleSelection: true) { result in
|
||||
if case .success(let urls) = result { handleFiles(urls) }
|
||||
}
|
||||
@ -643,7 +643,7 @@ struct KnowledgeDetailPage: View {
|
||||
}
|
||||
}
|
||||
}.padding(.horizontal, 20).padding(.bottom, 80) }.scrollIndicators(.hidden) }
|
||||
}.navigationBarTitleDisplayMode(.inline).toolbarBackground(.hidden, for: .navigationBar).animatedTabBarHide()}
|
||||
}.navigationBarTitleDisplayMode(.inline).toolbarBackground(.hidden, for: .navigationBar).toolbar(.hidden, for: .tabBar)}
|
||||
}
|
||||
struct ZXChip: View { let text: String; let color: Color
|
||||
var body: some View { Text(text).font(.system(size: 10, weight: .semibold)).foregroundColor(color).padding(.horizontal, 8).padding(.vertical, 2).background(color.opacity(0.12)).clipShape(Capsule()) }
|
||||
@ -683,7 +683,7 @@ struct ImportPage: View {
|
||||
}
|
||||
}.padding(.horizontal, 20).padding(.top, 8) }.scrollIndicators(.hidden) }
|
||||
}
|
||||
.navigationBarTitleDisplayMode(.inline).toolbarBackground(.hidden, for: .navigationBar).animatedTabBarHide()
|
||||
.navigationBarTitleDisplayMode(.inline).toolbarBackground(.hidden, for: .navigationBar).toolbar(.hidden, for: .tabBar)
|
||||
.disabled(isImporting)
|
||||
.task { do { let kbs = try await KnowledgeBaseService.shared.list(page: 1, limit: 1); kbId = kbs.first?.id } catch {} }
|
||||
.fileImporter(isPresented: $showFilePicker, allowedContentTypes: [.pdf, .plainText], allowsMultipleSelection: true) { result in
|
||||
@ -851,7 +851,7 @@ struct ImportReviewPage: View {
|
||||
.scrollIndicators(.hidden)
|
||||
}
|
||||
}}
|
||||
.navigationTitle("候选审批").navigationBarTitleDisplayMode(.inline).toolbarBackground(.hidden, for: .navigationBar).animatedTabBarHide()
|
||||
.navigationTitle("候选审批").navigationBarTitleDisplayMode(.inline).toolbarBackground(.hidden, for: .navigationBar).toolbar(.hidden, for: .tabBar)
|
||||
.disabled(isProcessing)
|
||||
.task { await load() }
|
||||
}
|
||||
@ -911,6 +911,6 @@ struct EditKnowledgePage: View {
|
||||
Task { _ = try? await KnowledgeItemService.shared.update(id: item.id, title: title, content: content, summary: nil) }
|
||||
} label: { Text("保存修改").font(.system(size: 14, weight: .bold)).foregroundColor(.white).frame(maxWidth: .infinity).frame(height: 52).background(ZXGradient.ctaPurple).clipShape(RoundedRectangle(cornerRadius: 16)) }
|
||||
}.padding(.horizontal, 20).padding(.top, 8).padding(.bottom, 80) }.scrollIndicators(.hidden) }
|
||||
}.navigationBarTitleDisplayMode(.inline).toolbarBackground(.hidden, for: .navigationBar).animatedTabBarHide()
|
||||
}.navigationBarTitleDisplayMode(.inline).toolbarBackground(.hidden, for: .navigationBar).toolbar(.hidden, for: .tabBar)
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,7 +142,7 @@ struct EditProfilePage: View {
|
||||
}
|
||||
.navigationTitle("编辑资料")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.animatedTabBarHide()
|
||||
.toolbar(.hidden, for: .tabBar)
|
||||
.toolbarBackground(.hidden, for: .navigationBar)
|
||||
.photosPicker(isPresented: $showPhotoPicker, selection: $selectedPhotoItem, matching: .images)
|
||||
.onChange(of: selectedPhotoItem) { _, item in
|
||||
|
||||
@ -39,6 +39,6 @@ struct FeedbackFormView: View {
|
||||
.disabled(isSubmitting)
|
||||
}.padding(.horizontal, 20).padding(.top, 8).padding(.bottom, 80)
|
||||
}.scrollIndicators(.hidden)
|
||||
}.navigationBarTitleDisplayMode(.inline).animatedTabBarHide().toolbarBackground(.hidden, for: .navigationBar)
|
||||
}.navigationBarTitleDisplayMode(.inline).toolbar(.hidden, for: .tabBar).toolbarBackground(.hidden, for: .navigationBar)
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,6 +49,6 @@ struct GoalSettingDetailView: View {
|
||||
.disabled(isSaving)
|
||||
}.padding(.horizontal, 20).padding(.top, 8).padding(.bottom, 80)
|
||||
}.scrollIndicators(.hidden)
|
||||
}.navigationBarTitleDisplayMode(.inline).animatedTabBarHide().toolbarBackground(.hidden, for: .navigationBar)
|
||||
}.navigationBarTitleDisplayMode(.inline).toolbar(.hidden, for: .tabBar).toolbarBackground(.hidden, for: .navigationBar)
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,6 +46,6 @@ struct MethodPreferenceView: View {
|
||||
.disabled(isSaving)
|
||||
}.padding(.horizontal, 20).padding(.top, 8).padding(.bottom, 80)
|
||||
}.scrollIndicators(.hidden)
|
||||
}.navigationBarTitleDisplayMode(.inline).animatedTabBarHide().toolbarBackground(.hidden, for: .navigationBar)
|
||||
}.navigationBarTitleDisplayMode(.inline).toolbar(.hidden, for: .tabBar).toolbarBackground(.hidden, for: .navigationBar)
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@ struct NotificationListView: View {
|
||||
.zxPullToRefresh { await refresh() }
|
||||
}
|
||||
.navigationTitle("消息中心")
|
||||
.navigationBarTitleDisplayMode(.inline).animatedTabBarHide()
|
||||
.navigationBarTitleDisplayMode(.inline).toolbar(.hidden, for: .tabBar)
|
||||
.toolbarBackground(.hidden, for: .navigationBar)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .topBarTrailing) {
|
||||
|
||||
@ -115,7 +115,7 @@ struct SettingsView: View {
|
||||
notificationEnabled = p.notificationEnabled ?? true
|
||||
reviewReminder = notificationEnabled
|
||||
}
|
||||
.navigationBarTitleDisplayMode(.inline).animatedTabBarHide().toolbarBackground(.hidden, for: .navigationBar)
|
||||
.navigationBarTitleDisplayMode(.inline).toolbar(.hidden, for: .tabBar).toolbarBackground(.hidden, for: .navigationBar)
|
||||
}
|
||||
|
||||
private func sectionHeader(_ text: String) -> some View {
|
||||
|
||||
@ -51,7 +51,7 @@ struct QuizListView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationTitle("测验").navigationBarTitleDisplayMode(.inline).animatedTabBarHide().toolbarBackground(.hidden, for: .navigationBar)
|
||||
.navigationTitle("测验").navigationBarTitleDisplayMode(.inline).toolbar(.hidden, for: .tabBar).toolbarBackground(.hidden, for: .navigationBar)
|
||||
.task { await load() }
|
||||
}
|
||||
|
||||
@ -164,7 +164,7 @@ struct QuizTakerView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationBarTitleDisplayMode(.inline).animatedTabBarHide().toolbarBackground(.hidden, for: .navigationBar)
|
||||
.navigationBarTitleDisplayMode(.inline).toolbar(.hidden, for: .tabBar).toolbarBackground(.hidden, for: .navigationBar)
|
||||
.task { await load() }
|
||||
}
|
||||
|
||||
@ -230,7 +230,7 @@ struct QuizResultView: View {
|
||||
}.scrollIndicators(.hidden)
|
||||
}
|
||||
}
|
||||
.navigationBarTitleDisplayMode(.inline).animatedTabBarHide().toolbarBackground(.hidden, for: .navigationBar)
|
||||
.navigationBarTitleDisplayMode(.inline).toolbar(.hidden, for: .tabBar).toolbarBackground(.hidden, for: .navigationBar)
|
||||
.task { await load() }
|
||||
}
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@ struct LearningSessionView: View {
|
||||
bottomBar
|
||||
}.ignoresSafeArea(edges: .bottom)
|
||||
}
|
||||
.navigationBarTitleDisplayMode(.inline).animatedTabBarHide()
|
||||
.navigationBarTitleDisplayMode(.inline).toolbar(.hidden, for: .tabBar)
|
||||
.toolbarBackground(.hidden, for: .navigationBar)
|
||||
.onReceive(timer) { _ in
|
||||
if isRunning { elapsed += 1 }
|
||||
|
||||
@ -40,7 +40,7 @@ struct ReviewCardView: View {
|
||||
.scrollIndicators(.hidden)
|
||||
}
|
||||
}
|
||||
.navigationBarTitleDisplayMode(.inline).animatedTabBarHide()
|
||||
.navigationBarTitleDisplayMode(.inline).toolbar(.hidden, for: .tabBar)
|
||||
.toolbarBackground(.hidden, for: .navigationBar)
|
||||
.task { await viewModel.loadDueCards() }
|
||||
.overlay {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user