SwiftUI父视图用.large标题模式时.refreshable默认ProgressView不显示
iOS15下List.refreshable进度条不显示的解决方案
问题回顾
在iOS15开发场景中,遇到以下异常:
- 带有List的
JobListingView添加.refreshable修饰符后,数据能正常加载,但下拉刷新的默认ProgressView不显示 - 大屏设备(如iPad)上进度条可正常显示,此时导航栏标题为
inline模式(原配置为.automatic) - 视图跳转链:
LoginView→SelectView→JobListingView,LoginView中定义NavigationView并隐藏导航栏;若SelectView设置.navigationBarTitleDisplayMode(.large),后续JobListingView无论自身设置何种标题模式,刷新进度条都无法显示
问题原因
这是iOS15中NavigationView的标题模式状态传递导致的布局冲突:当父视图(SelectView)使用.large大标题模式时,子视图(JobListingView)的List顶部刷新指示器会被导航栏的大标题区域遮挡,或者导航栏的布局状态影响了List的可滚动区域计算,导致进度条无法正常显示。
解决方案
方案1:显式重置子视图导航栏状态
在跳转到JobListingView的NavigationLink中,直接给目标视图指定导航栏标题模式,强制覆盖父视图的状态:
// 修改SelectView中的NavigationLink NavigationLink(destination: JobListingView() .navigationBarTitleDisplayMode(.inline)){ SelectItemView(name: "Jobs", icon: "icAssignment") }
即使SelectView用了.large模式,这个设置会强制JobListingView的导航栏切换为inline,让刷新进度条回到可见区域。
方案2:调整List的内容内边距
如果需要保留JobListingView的.large标题模式,可以给List添加顶部内边距,让刷新指示器避开导航栏遮挡:
// 修改JobListingView的List部分 List(viewModel.jobListDTO, id: \.id) { job in JobItemView(item: job) .listRowSeparator(.hidden) } .padding(.top, 10) // 添加顶部内边距,让刷新指示器可见 .refreshable { await viewModel.requestJobListing() }
方案3:修正NavigationView层级结构
LoginView中隐藏导航栏的方式可能导致导航栈状态异常,调整为仅在登录视图内容上隐藏导航栏,而不是整个NavigationView的子视图:
// 修改LoginView的body public var body: some View { NavigationView{ ZStack{ // 单独给登录内容视图设置导航栏隐藏 LoginView(viewModel: viewModel) .background(Color(.white)) .navigationBarHidden(true) NavigationLink(destination: SelectView(), isActive: $viewModel.loggedIn){ EmptyView() } } } }
同时在SelectView中,确保导航栏的状态是正确的,避免异常状态传递到后续视图。
方案4:通过UIKit外观调整(兜底方案)
如果以上方案都无效,可通过UIKit的外观设置强制调整List的内容适配行为:
// 在JobListingView的init方法中添加 init() { UITableView.appearance().contentInsetAdjustmentBehavior = .always }
这个设置会让List的内容自动适配导航栏和状态栏的高度,确保刷新指示器不会被遮挡。
内容的提问来源于stack exchange,提问作者sebasira
相关产品推荐
相关产品推荐

