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

SwiftUI中为DisclosureGroup添加滚动固定顶部标题的方法

实现DisclosureGroup滚动时置顶标题的方案

DisclosureGroup本身没有原生的置顶header功能,但可以通过以下方式实现需求,同时保留它的展开/折叠便捷性:

核心思路

通过监听ScrollView的滚动偏移,结合自定义置顶标题视图,根据DisclosureGroup的展开状态动态控制标题的显示与固定位置。

完整实现代码

import SwiftUI

struct PinnedDisclosureDemo: View {
    @State private var isExpanded = false
    @State private var scrollOffset: CGFloat = 0
    
    // 模拟长文本内容
    private let longContent = String(repeating: "这是一段用于测试的长文本内容,重复多次以填满屏幕。", count: 60)
    
    var body: some View {
        ScrollView {
            // 监听滚动偏移的占位视图
            GeometryReader { proxy in
                Color.clear
                    .preference(key: ScrollOffsetKey.self, value: proxy.frame(in: .named("scrollContainer")).minY)
            }
            .frame(height: 0)
            
            // 隐藏默认label的DisclosureGroup
            DisclosureGroup(isExpanded: $isExpanded) {
                Text(longContent)
                    .padding()
                    .font(.body)
            } label: {
                EmptyView()
            }
        }
        .coordinateSpace(name: "scrollContainer")
        .onPreferenceChange(ScrollOffsetKey.self) { offset in
            scrollOffset = offset
        }
        // 叠加置顶标题
        .overlay(alignment: .top) {
            if isExpanded {
                Text("First description")
                    .font(.headline)
                    .padding(.vertical, 8)
                    .padding(.horizontal, 16)
                    .background(Color(UIColor.systemBackground))
                    .cornerRadius(6)
                    .shadow(color: .black.opacity(0.1), radius: 2, x: 0, y: 1)
                    .offset(y: max(0, -scrollOffset))
            }
        }
        // 初始展开可选
        .onAppear {
            isExpanded = true
        }
    }
}

// 自定义PreferenceKey用于传递滚动偏移
private struct ScrollOffsetKey: PreferenceKey {
    static var defaultValue: CGFloat = 0
    static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
        value = nextValue()
    }
}

#Preview {
    PinnedDisclosureDemo()
}

关键说明

  1. 滚动偏移监听:利用GeometryReader和自定义PreferenceKey捕获ScrollView的滚动位置,为标题固定提供依据。
  2. 动态标题位置:通过offset(y: max(0, -scrollOffset))让标题在滚动时保持在顶部,当滚动到顶部时恢复原位置。
  3. 保留DisclosureGroup特性:隐藏默认label后,仍可通过绑定的isExpanded状态控制展开/折叠,不影响原有便捷操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 12:17:20