SwiftUI实现滚动过文本后移至NavigationTitle的方法
SwiftUI实现Apple Music式滚动标题过渡效果(无需GeometryReader/ScrollViewReader)
当然可以实现,在iOS 17+版本的SwiftUI里,不用GeometryReader或ScrollViewReader也能轻松搞定——靠ScrollView新增的onScrollChange方法就能监听滚动偏移,配合导航栏自定义视图实现平滑过渡效果。
实现思路
核心逻辑很直接:
- 页面内保留一个和导航栏标题完全一致的文本视图
- 监听滚动偏移,当页面内的标题滚出导航栏区域时,让导航栏标题逐渐显示,同时页面内的标题逐渐隐藏
- 通过调整透明度和位置偏移,实现无缝的过渡动画
完整代码示例
import SwiftUI struct ScrollTitleTransitionView: View { // 模拟列表数据 private let songs = (1...50).map { "第\($0)首歌" } // 记录滚动偏移量 @State private var scrollOffset: CGFloat = 0 // 统一的标题文本 private let titleText = "我的最爱歌单" // 导航栏标题区域的基准高度(可根据实际需求调整) private let navBarHeight: CGFloat = 44 var body: some View { NavigationStack { ScrollView { VStack(alignment: .leading, spacing: 16) { // 页面内的标题,随滚动逐渐消失 Text(titleText) .font(.largeTitle) .fontWeight(.bold) .padding() // 根据滚动偏移调整透明度和位置 .opacity(max(0, 1 - (scrollOffset / navBarHeight))) .offset(y: min(0, -scrollOffset)) // 列表内容 ForEach(songs, id: \.self) { song in Text(song) .padding(.horizontal) .frame(maxWidth: .infinity, alignment: .leading) .padding(.vertical, 8) } } } .scrollContentBackground(.hidden) // iOS17+新增API,直接监听滚动偏移 .onScrollChange { context in scrollOffset = context.contentOffset.y } .navigationTitle("") .toolbar { // 导航栏标题,随滚动逐渐显示 ToolbarItem(placement: .principal) { Text(titleText) .font(.title) .fontWeight(.bold) .opacity(max(0, (scrollOffset - navBarHeight) / navBarHeight)) } } } } } #Preview { ScrollTitleTransitionView() }
关键细节说明
onScrollChange:iOS17新增的原生API,无需额外布局读取器就能直接获取ScrollView的滚动偏移量- 透明度过渡:当滚动偏移小于导航栏高度时,页面内标题保持完全显示;超过阈值后,导航栏标题逐步显现,页面内标题逐步隐藏
- 位置偏移:页面内标题随滚动向上偏移,避免和导航栏标题出现重叠,让过渡更自然流畅
这个实现和你参考的Apple Music滚动标题逻辑完全一致,代码简洁且未使用禁用的API。
内容的提问来源于stack exchange,提问作者Leo Klaus
相关产品推荐
相关产品推荐

