You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI:阻止内容滚动到粘性Section Header后方的问题

解决方案

要实现RewardsTabItems固定在顶部且内容不滚动到其后方的效果,你可以调整视图层级,将分段控件从滚动容器中移出并固定在顶部,同时给滚动视图设置顶部内边距避免内容遮挡。具体修改如下:

  1. 移除原LazyVStack中用于固定头部的Section结构,将RewardsTabItems从分段容器的header中独立出来
  2. 使用ZStack将滚动视图和分段控件分层,让分段控件覆盖在滚动视图顶部
  3. 给滚动视图设置顶部内边距,值等于分段控件的高度,确保内容从分段控件下方开始滚动

修改后的代码示例:

// 先定义分段控件的固定高度,根据你的实际需求调整
private static let tabItemsHeight: CGFloat = 48

ZStack(alignment: .top) {
    ScrollView {
        LazyVStack(spacing: 0) {
            // 原有的顶部Surface视图
            if let surfaceData = viewModel.surface {
                VStack {
                    RewardsSurfaceView(surface: surfaceData)
                    Divider()
                        .frame(width: UIScreen.main.bounds.width, height: 0.5)
                        .background(.gray)
                        .padding(.bottom, AppAppearance.Spacing.smallRegular)
                }
            }
            
            // 分段内容容器
            RewardsTabContainer(
                tabs: tabs,
                viewModel: viewModel
            )
            .frame(minHeight: Self.tabsContainerHeight)
        }
    }
    // 设置顶部内边距,让内容从分段控件下方开始
    .contentInsets(.init(top: Self.tabItemsHeight, leading: 0, bottom: 0, trailing: 0))
    .customNavigationBar(
        navigationType: .pushed,
        background: Image(.rewardsBG)
            .resizable()
            .ignoresSafeArea(.container, edges: .top)
            .background(Color.black)
            .accessibilityLabel(AccessibilityLabel.rewardsBackgroundImage)
    )
    
    // 固定在顶部的分段控件
    RewardsTabItems(tabs: tabs, viewModel: viewModel)
        .frame(height: Self.tabItemsHeight)
}

原理说明

  • 分段控件通过ZStack层级覆盖在滚动视图上方,始终保持在顶部位置
  • 滚动视图的顶部内边距确保内容不会被分段控件遮挡,同时滚动时内容只会在分段控件下方移动,不会跑到其后方
  • 由于分段控件直接使用自定义导航栏的背景,无需额外设置背景色,符合你的需求

内容的提问来源于stack exchange,提问作者Shikha Sharma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 10:42:48