SwiftUI标签页视图中如何一致显示视图状态?
问题分析与解决方案
核心问题
两个标签页(关注/粉丝)共用同一个ViewModel的全局state属性,导致状态互相覆盖;同时视图的Equatable实现未包含关键状态/数据,状态变化时视图无法正确刷新,最终出现空白屏幕。
修复步骤
1. 重构ViewModel:拆分独立状态
将原有的单个state拆分为followingState和followerState,分别管理两个标签的加载/完成/空状态,避免互相干扰:
import Foundation import SwiftUI class FollowListViewModel: ObservableObject { let user: User @Published var followingUsers = [User]() @Published var followerUsers = [User]() @Published var users = [User]() private let service = FeedService() private let userService = UserService() // 拆分独立状态 @Published var followingState: State = .loading @Published var followerState: State = .loading init(user: User) { self.user = user } enum State { case loading case loaded case empty } func fetchFollowingList() { guard let uid = user.id else { return } followingState = .loading // 加载前重置状态 service.fetchFollowingList(forUid: uid) { users in self.followingUsers = users.filter({ $0.id != uid }) if self.followingUsers.count > 0 { self.followingState = .loaded } else { self.fetchUsers(completion: { self.followingState = .empty }) } } } func fetchFollowerList() { guard let uid = user.id else { return } followerState = .loading // 加载前重置状态 service.fetchFollowerList(forUid: uid) { users in self.followerUsers = users if self.followerUsers.count > 0 { self.followerState = .loaded } else { self.fetchUsers(completion: { self.followerState = .empty }) } } } // 添加完成回调,确保状态仅更新当前标签的对应值 func fetchUsers(completion: @escaping () -> Void) { userService.fetchUsers { users in self.users = users completion() } } }
2. 修复FollowingView:绑定独立状态+修正Equatable
import SwiftUI struct FollowingView: View, Equatable { @ObservedObject var viewModel: FollowListViewModel @State var didRefresh = false @Binding var followTab: Int static func == (lhs: FollowingView, rhs: FollowingView) -> Bool { // 比较所有影响视图显示的关键属性,确保状态变化时视图刷新 lhs.viewModel.followingState == rhs.viewModel.followingState && lhs.viewModel.followingUsers == rhs.viewModel.followingUsers && lhs.viewModel.users == rhs.viewModel.users && lhs.didRefresh == rhs.didRefresh } var body: some View { VStack { switch viewModel.followingState { case .loading: Spacer() ProgressView() Spacer() case .loaded: ScrollView (.vertical, showsIndicators: false) { PullToRefresh(coordinateSpaceName: "pullToRefreshFollowing") { viewModel.fetchFollowingList() } LazyVStack { ForEach(viewModel.followingUsers) { user in NavigationLink( destination: LazyView(ProfileView(user: user)), label: { ListItemUser(user: user).buttonHidden() .padding(.top, 12) } ) } } }.coordinateSpace(name: "pullToRefreshFollowing") case .empty: FollowEmptyStateView(viewModel: viewModel, followTab: $followTab) } } .onAppear { viewModel.fetchFollowingList() } } }
3. 修复FollowerView:绑定独立状态+修正Equatable
import SwiftUI struct FollowerView: View, Equatable { @ObservedObject var viewModel: FollowListViewModel @State var didRefresh = false @Binding var followTab: Int static func == (lhs: FollowerView, rhs: FollowerView) -> Bool { // 比较所有影响视图显示的关键属性,确保状态变化时视图刷新 lhs.viewModel.followerState == rhs.viewModel.followerState && lhs.viewModel.followerUsers == rhs.viewModel.followerUsers && lhs.viewModel.users == rhs.viewModel.users && lhs.didRefresh == rhs.didRefresh } var body: some View { VStack { switch viewModel.followerState { case .loading: Spacer() ProgressView() Spacer() case .loaded: ScrollView (.vertical, showsIndicators: false) { PullToRefresh(coordinateSpaceName: "pullToRefreshFollower") { viewModel.fetchFollowerList() } LazyVStack { ForEach(viewModel.followerUsers) { user in NavigationLink( destination: LazyView(ProfileView(user: user)), label: { ListItemUser(user: user).buttonHidden() .padding(.top, 12) } ) } } }.coordinateSpace(name: "pullToRefreshFollower") case .empty: FollowEmptyStateView(viewModel: viewModel, followTab: $followTab) } } .onAppear { viewModel.fetchFollowerList() } } }
关键修复点说明
- 状态隔离:拆分
followingState和followerState,让两个标签的状态完全独立,不会互相覆盖。 - 视图刷新逻辑修正:更新
Equatable实现,包含所有影响视图显示的属性(状态、用户列表等),确保状态变化时SwiftUI能正确触发视图刷新。 - 加载状态重置:每次发起请求前重置对应标签的状态,避免旧状态干扰新请求的显示。
- CoordinateSpace冲突解决:给两个视图的下拉刷新设置不同的坐标空间名称,避免功能异常。
内容的提问来源于stack exchange,提问作者amelia
相关产品推荐
相关产品推荐

