如何在不同滚动状态下修改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
相关产品推荐
相关产品推荐

