Files
e-party-iOS/yana/Views/MainView.swift
edwinQQQ 4ff92c8c4d feat: 修复MainView Tab切换问题并优化MeView逻辑
- 新增MainView Tab切换问题分析文档,详细描述问题原因及解决方案。
- 优化BottomTabView的绑定逻辑,简化状态管理,确保Tab切换时状态正确更新。
- 在MeView中实现用户信息加载逻辑调整,确保动态列表仅在首次进入时加载,并添加错误处理视图。
- 创建EmptyStateView组件,提供统一的空状态展示和重试功能。
- 增强调试信息输出,便于后续问题排查和用户体验提升。
2025-08-05 15:51:07 +08:00

153 lines
5.7 KiB
Swift

import SwiftUI
import ComposableArchitecture
struct MainView: View {
let store: StoreOf<MainFeature>
var onLogout: (() -> Void)? = nil
var body: some View {
WithPerceptionTracking {
InternalMainView(store: store)
.onChange(of: store.isLoggedOut) { _, isLoggedOut in
if isLoggedOut {
onLogout?()
}
}
}
}
}
struct InternalMainView: View {
let store: StoreOf<MainFeature>
@State private var path: [MainFeature.Destination] = []
init(store: StoreOf<MainFeature>) {
self.store = store
_path = State(initialValue: store.withState { $0.navigationPath })
}
var body: some View {
WithPerceptionTracking {
NavigationStack(path: $path) {
GeometryReader { geometry in
contentView(geometry: geometry)
.navigationDestination(for: MainFeature.Destination.self) { destination in
DestinationView(destination: destination, store: self.store)
}
.onChange(of: path) { _, path in
store.send(.navigationPathChanged(path))
}
.onChange(of: store.navigationPath) { _, navigationPath in
if path != navigationPath {
path = navigationPath
}
}
.onAppear {
debugInfoSync("🚀 MainView onAppear")
debugInfoSync(" 当前selectedTab: \(store.selectedTab)")
store.send(.onAppear)
}
}
}
}
}
struct DestinationView: View {
let destination: MainFeature.Destination
let store: StoreOf<MainFeature>
var body: some View {
switch destination {
case .appSetting:
IfLetStore(
store.scope(state: \.appSettingState, action: \.appSettingAction),
then: { store in
WithPerceptionTracking {
AppSettingView(store: store)
}
},
else: { Text("appSettingState is nil") }
)
case .testView:
TestView()
}
}
}
private func contentView(geometry: GeometryProxy) -> some View {
WithPerceptionTracking {
ZStack {
//
Image("bg")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.clipped()
.ignoresSafeArea(.all)
//
MainContentView(
store: store,
selectedTab: store.selectedTab
)
.onChange(of: store.selectedTab) { _, newTab in
debugInfoSync("🔄 MainView selectedTab changed: \(newTab)")
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.padding(.bottom, 80) //
// -
VStack {
Spacer()
BottomTabView(selectedTab: Binding(
get: {
// MainFeature.TabBottomTabView.Tab
let currentTab = store.selectedTab == .feed ? Tab.feed : Tab.me
debugInfoSync("🔍 BottomTabView get: MainFeature.Tab.\(store.selectedTab) → BottomTabView.Tab.\(currentTab)")
return currentTab
},
set: { newTab in
// BottomTabView.TabMainFeature.Tab
let mainTab: MainFeature.Tab = newTab == .feed ? .feed : .other
debugInfoSync("🔍 BottomTabView set: BottomTabView.Tab.\(newTab) → MainFeature.Tab.\(mainTab)")
store.send(.selectTab(mainTab))
}
))
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottom)
.padding(.bottom, 100)
.ignoresSafeArea(.keyboard, edges: .bottom)
// API Loading
APILoadingEffectView()
}
}
}
}
struct MainContentView: View {
let store: StoreOf<MainFeature>
let selectedTab: MainFeature.Tab
var body: some View {
WithPerceptionTracking {
let _ = debugInfoSync("📱 MainContentView selectedTab: \(selectedTab)")
let _ = debugInfoSync(" 与store.selectedTab一致: \(selectedTab == store.selectedTab)")
Group {
if selectedTab == .feed {
FeedListView(store: store.scope(
state: \.feedList,
action: \.feedList
))
} else if selectedTab == .other {
MeView(
store: store.scope(
state: \.me,
action: \.me
),
showCloseButton: false // MainView
)
} else {
CustomEmptyView(onRetry: {})
}
}
}
}
}