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

SwiftUI:如何让导航栏标题及按钮随滚动时导航栏显隐?

实现导航栏标题/按钮随滚动动态显示

完全可以实现这个需求,下面分两种场景给出具体实现方案:

方案一:iOS 17+(推荐)

利用iOS 17新增的scrollPosition API直接跟踪列表滚动位置,逻辑更简洁:

struct ContentView: View {
    @State private var showNavElements = false
    @State private var scrollPosition: Int?
    
    var body: some View {
        TabView {
            NavigationStack {
                List {
                    // 头部视图,设置唯一ID用于滚动跟踪
                    HStack {
                        Spacer()
                        Text("Header")
                        Spacer()
                    }
                    .frame(height: 300)
                    .background(.red)
                    .listRowInsets(EdgeInsets())
                    .id(-1)
                    
                    // 列表项
                    ForEach(1..<100) { index in
                        Text("\(index)")
                            .id(index)
                    }
                }
                .listStyle(.plain)
                .ignoresSafeArea(.all, edges: .top)
                // 绑定滚动位置
                .scrollPosition(id: $scrollPosition)
                // 根据滚动位置切换导航元素显示状态
                .onChange(of: scrollPosition) { _, newPos in
                    showNavElements = newPos != nil && newPos! >= 1
                }
                // 动态显示/隐藏导航标题
                .navigationTitle(showNavElements ? "Navigation Title" : "")
                .navigationBarTitleDisplayMode(.inline)
                // 控制导航栏背景显示
                .toolbarBackground(showNavElements ? .visible : .hidden, for: .navigationBar)
                .toolbarBackground(.white, for: .navigationBar)
                // 动态显示导航按钮
                .toolbar {
                    if showNavElements {
                        Button("设置") {
                            // 按钮逻辑
                        }
                    }
                }
            }
        }
    }
}

逻辑说明

  • 给头部视图和每个列表项设置唯一id,通过scrollPosition跟踪当前滚动到的元素ID
  • 当滚动到第一个列表项(index≥1)时,触发showNavElements为true,此时导航栏的标题、背景和按钮自动显示;滚动回头部时自动隐藏

方案二:兼容iOS 16及以下

对于低版本系统,用GeometryReader结合自定义PreferenceKey监听滚动偏移量:

struct ContentView: View {
    @State private var showNavElements = false
    
    var body: some View {
        TabView {
            NavigationStack {
                List {
                    HStack {
                        Spacer()
                        Text("Header")
                        Spacer()
                    }
                    .frame(height: 300)
                    .background(.red)
                    .listRowInsets(EdgeInsets())
                    
                    ForEach(1..<100) { index in
                        Text("\(index)")
                    }
                }
                .listStyle(.plain)
                .ignoresSafeArea(.all, edges: .top)
                // 监听滚动偏移
                .overlay(
                    GeometryReader { proxy in
                        Color.clear
                            .preference(key: ScrollOffsetKey.self, value: proxy.frame(in: .named("scroll")).minY)
                    }
                )
                .coordinateSpace(name: "scroll")
                // 根据偏移量切换显示状态
                .onPreferenceChange(ScrollOffsetKey.self) { offset in
                    // 阈值可根据头部高度调整,这里设为-200表示滚动超过头部下方200pt时显示
                    showNavElements = offset < -200
                }
                .navigationTitle(showNavElements ? "Navigation Title" : "")
                .navigationBarTitleDisplayMode(.inline)
                .toolbarBackground(showNavElements ? .visible : .hidden, for: .navigationBar)
                .toolbar {
                    if showNavElements {
                        Button("设置") {}
                    }
                }
            }
        }
    }
}

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

逻辑说明

  • 通过GeometryReader获取列表在自定义坐标空间内的偏移量,用PreferenceKey传递给视图
  • 当偏移量小于设定阈值(比如-200)时,判断用户已经滚动到头部下方,触发导航元素显示

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 08:12:04