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

如何在不同滚动状态下修改Back按钮与ToolbarItem的颜色

实现导航栏按钮随滚动动态变色

核心逻辑

通过监听页面滚动状态,动态切换导航栏的tint颜色,同时配合导航栏背景的显示/隐藏逻辑,实现初始状态按钮为白色、滚动后变为蓝色的效果。系统返回按钮和自定义ToolbarItem会自动继承导航栏的tint颜色,无需单独设置。

iOS 17+ 简洁实现

struct ContentView: View {
    @State private var isScrolled = false
    @State private var scrollID: Int?

    var body: some View {
        NavigationStack {
            ScrollView {
                LazyVStack(spacing: 20) {
                    ForEach(0..<30) { index in
                        Text("第 \(index+1) 条内容")
                            .frame(maxWidth: .infinity)
                            .padding()
                            .background(Color.gray.opacity(0.1))
                    }
                }
                .padding()
                .scrollPosition(id: $scrollID)
            }
            .navigationTitle("示例页面")
            .toolbar {
                ToolbarItem(placement: .topBarTrailing) {
                    Button(action: {}) {
                        Image(systemName: "ellipsis")
                    }
                }
            }
            // 根据滚动状态切换按钮颜色
            .tint(isScrolled ? .blue : .white)
            // 控制导航栏背景显示
            .toolbarBackground(isScrolled ? .visible : .hidden, for: .navigationBar)
            .toolbarBackground(Color.white, for: .navigationBar)
        }
        .onChange(of: scrollID) {
            isScrolled = scrollID != nil
        }
    }
}

iOS 16及以下兼容实现

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

struct ContentView: View {
    @State private var isScrolled = false

    init() {
        // 配置初始导航栏透明外观
        let appearance = UINavigationBarAppearance()
        appearance.backgroundColor = .clear
        appearance.titleTextAttributes = [.foregroundColor: UIColor.white]
        
        UINavigationBar.appearance().scrollEdgeAppearance = appearance
        UINavigationBar.appearance().standardAppearance = appearance
    }

    var body: some View {
        NavigationView {
            ScrollView {
                // 隐藏的GeometryReader监听滚动偏移
                GeometryReader { proxy in
                    Color.clear
                        .preference(key: ScrollOffsetKey.self, value: proxy.frame(in: .named("scroll")).minY)
                }
                .frame(height: 0)

                LazyVStack(spacing: 20) {
                    ForEach(0..<30) { index in
                        Text("第 \(index+1) 条内容")
                            .frame(maxWidth: .infinity)
                            .padding()
                            .background(Color.gray.opacity(0.1))
                    }
                }
                .padding()
            }
            .coordinateSpace(name: "scroll")
            .navigationTitle("示例页面")
            .toolbar {
                ToolbarItem(placement: .topBarTrailing) {
                    Button(action: {}) {
                        Image(systemName: "ellipsis")
                    }
                }
            }
            .tint(isScrolled ? .blue : .white)
            .toolbarBackground(isScrolled ? .visible : .hidden, for: .navigationBar)
            .toolbarBackground(Color.white, for: .navigationBar)
            .onPreferenceChange(ScrollOffsetKey.self) { offset in
                // 偏移量小于0时判定为已滚动
                isScrolled = offset < 0
            }
        }
    }
}

关键说明

  • .tint():统一控制系统返回按钮和自定义ToolbarItem的颜色,无需单独设置按钮的前景色
  • .toolbarBackground():配合滚动状态切换导航栏背景的显示/隐藏,实现背景出现时按钮变色的联动
  • 滚动监听:iOS17+用scrollPosition更简洁,老版本通过PreferenceKey获取滚动偏移量判断滚动状态

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 02:55:28