SwiftUI如何实现图标与标题对齐的App Store风格滚动导航栏
SwiftUI 实现类App Store自适应滚动标题栏
效果参考:
- 初始状态(大标题+右侧功能按钮):

- 滚动后状态(内嵌标题+按钮隐藏):

核心实现思路
完全基于系统原生导航组件实现,不需要自定义导航栏就能匹配App Store的原生交互和对齐规则:
- 监听ScrollView纵向滚动偏移,判断是否达到大标题折叠阈值
- 动态切换导航标题的显示模式(大标题/内嵌标题)
- 同步控制右侧工具栏按钮的显隐,加平滑过渡动画避免布局跳动
- 沿用系统导航栏默认布局规则,不需要手动调整标题、图标位置,自动完成对齐适配
具体实现代码
- 首先定义滚动偏移读取工具,通过SwiftUI的PreferenceKey传递滚动位置:
struct ScrollOffsetPreferenceKey: PreferenceKey { static var defaultValue: CGFloat = 0 static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { value = nextValue() } }
- 页面核心实现:
import SwiftUI struct AppStoreStyleNavBar: View { // 存储当前滚动偏移值 @State private var scrollOffset: CGFloat = 0 // 大标题折叠阈值,可根据实际场景微调,35-45区间基本匹配系统触发时机 private let foldTriggerOffset: CGFloat = 40 var body: some View { NavigationStack { ScrollView { // 顶部插入零高度探测视图,用于读取滚动偏移 GeometryReader { proxy in Color.clear .preference( key: ScrollOffsetPreferenceKey.self, value: proxy.frame(in: .named("scrollView")).minY ) } .frame(height: 0) // 此处放置页面实际滚动内容,比如应用介绍、截图、评价模块 // VStack(spacing: 16) { ... } } .coordinateSpace(name: "scrollView") .onPreferenceChange(ScrollOffsetPreferenceKey.self) { newValue in // 偏移取反,向下滚动时offset为正值 scrollOffset = -newValue } // 动态切换标题显示模式 .navigationTitle("应用详情") .toolbarTitleDisplayMode( scrollOffset > foldTriggerOffset ? .inline : .large ) .toolbar { // 右侧功能按钮,用透明度控制显隐比直接条件移除更顺滑,不会导致布局跳变 ToolbarItem(placement: .topBarTrailing) { Button { // 分享按钮逻辑 } label: { Image(systemName: "square.and.arrow.up") } .opacity(scrollOffset > foldTriggerOffset ? 0 : 1) .disabled(scrollOffset > foldTriggerOffset) .animation(.easeOut(duration: 0.15), value: scrollOffset) } ToolbarItem(placement: .topBarTrailing) { Button { // 更多操作按钮逻辑 } label: { Image(systemName: "ellipsis.circle") } .opacity(scrollOffset > foldTriggerOffset ? 0 : 1) .disabled(scrollOffset > foldTriggerOffset) .animation(.easeOut(duration: 0.15), value: scrollOffset) } } // 隐藏导航栏默认纯色背景,匹配App Store的透明/毛玻璃滚动效果 .toolbarBackground(.hidden, for: .navigationBar) } } }
适配注意点
- 不要手动给标题或者按钮加额外边距、位置偏移,系统原生Toolbar布局会自动处理大标题、右侧按钮的基线对齐,手动调整反而会出现错位
- 如果需要适配iOS15及以下版本,把
.toolbarTitleDisplayMode替换成.navigationBarTitleDisplayMode即可,逻辑完全一致 - 折叠阈值可以根据页面实际大标题样式微调,如果使用了自定义字体的大标题,适当调整
foldTriggerOffset数值,保证和系统折叠时机同步
内容的提问来源于stack exchange,提问作者julesgzel
相关产品推荐
相关产品推荐

