嵌入NavigationView的Geometry View顶部间距问题求助
我参照教程设计SwiftUI视图,将其嵌入NavigationView后,"TOP NEWS"文本与导航栏之间出现了多余的间距。尝试修改标题样式和代码中的数值参数,问题仍未解决,作为iOS初级开发者寻求帮助。
以下是我的代码(与教程代码略有不同):
struct allArticlesListView: View { @State var title = "Sports" @Environment(\.colorScheme) var colorScheme @State var isGotData = false // let fetchData = FetchNews() @State var articles : [Article] = [] var body: some View { if isGotData { ScrollView(.vertical){ VStack(spacing : 0){ VStack(alignment: .leading,spacing: 15) { HStack{ Text("TOP NEWS") .font(.largeTitle.bold()) .frame(height: 45) .padding(.horizontal,15) } GeometryReader{ let rect = $0.frame(in: .scrollView(axis : .vertical)) let minY = rect.minY let topValue : CGFloat = 75.0 let offset = min(minY - topValue, 0) let progress = max(min( -offset / topValue, 1), 0) let scale = 1 + progress ZStack{ Rectangle() .fill(Color.blue) .overlay(alignment: .leading) { Circle() .fill(Color.blue) .overlay { Circle() .fill(.white.opacity(0.2)) } .scaleEffect(2,anchor: .topLeading) .offset(x: -50,y: -40) } .clipShape(RoundedRectangle(cornerRadius: 25,style: .continuous)) .scaleEffect(scale,anchor: .bottom) VStack(alignment: .center, spacing: 4){ Text("\(title)") .font(.title.bold()) } .foregroundStyle(.white) .frame(maxWidth: .infinity, alignment : .leading) .padding(15) .offset(y : progress * -25 ) } .offset(y : -offset) //Moving till top value .offset(y : progress * -topValue) } .padding(.horizontal,15) .containerRelativeFrame(.horizontal) .frame(height: 125) LazyVStack(spacing: 15) { ForEach(articles, id: \.self) { article in NavigationLink(destination: detailedArticleView(singleArticle: article)) { VStack(alignment: .leading) { ArticleView(article: article, category: title) } } } } .padding(15) .mask{ Rectangle() .visualEffect { content, geometryProxy in content .offset(y : backgroundLimitOffset(geometryProxy)) } } .background{ GeometryReader { let rect = $0.frame(in: .scrollView) let minY = min(rect.minY - 125, 0) let progress = max(min(-minY / 25, 1), 0) RoundedRectangle(cornerRadius: 30 * progress,style: .continuous) .fill(colorScheme == .dark ? .black : .white) .overlay(alignment: .top){ } /// Limiting Background Scroll below the header .visualEffect { content, geometryProxy in content .offset(y : backgroundLimitOffset(geometryProxy)) } } } } .padding(.vertical,15) } } .scrollTargetBehavior(CustomScrollBehaviourSample()) .scrollIndicators(.hidden) .background { LinearGradient(colors: [.green, .cyan, .cyan ,.indigo], startPoint: .topLeading, endPoint: .bottomTrailing) .ignoresSafeArea() } }else{ ProgressView() .onAppear { // fetchData.fetchData(category: title) { allArticles in // self.articles = allArticles // print("fetched the data") // isGotData = true // } fetch() } } } /// Background Limit Offset func backgroundLimitOffset(_ proxy : GeometryProxy) -> CGFloat { let minY = proxy.frame(in: .scrollView).minY return minY < 75 ? -minY + 75 : 0 } func fetch(){ if let filePath = Bundle.main.url(forResource: "dummy.json", withExtension: ""){ if let data = try? Data(contentsOf: filePath){ if let content = try? JSONDecoder().decode(Welcome.self, from: data){ articles = content.articles isGotData = true }else{ print("error in data decoding") } }else{ print("error in data fetching") } }else{ print("error in file path") } } } /// Custom Scroll Target Behaviour /// AKA scrollWillEndDragging in UIKit struct CustomScrollBehaviourSample : ScrollTargetBehavior { func updateTarget(_ target: inout ScrollTarget, context: TargetContext) { if target.rect.minY < 75 { target.rect = .zero } } }
解决方案
针对这个间距问题,可以从以下几个方面调整代码:
处理NavigationView与ScrollView的安全区域冲突
NavigationView默认会给子视图添加上部安全区域间距,而你的ScrollView背景已经用了.ignoresSafeArea(),两者叠加会产生多余间距。给ScrollView添加.edgesIgnoringSafeArea(.top),让它忽略顶部安全区域:ScrollView(.vertical){ // 原有内容 } .scrollTargetBehavior(CustomScrollBehaviourSample()) .scrollIndicators(.hidden) .edgesIgnoringSafeArea(.top) // 新增这一行 .background { LinearGradient(colors: [.green, .cyan, .cyan ,.indigo], startPoint: .topLeading, endPoint: .bottomTrailing) .ignoresSafeArea() }移除不必要的垂直padding
外层VStack的.padding(.vertical,15)会给整个内容块添加上下间距,直接导致"TOP NEWS"上方多出15pt空白。把它改成只给底部加padding:VStack(alignment: .leading,spacing: 15) { // "TOP NEWS"及后续内容 } .padding(.bottom,15) // 替换原来的.padding(.vertical,15)调整自定义滚动行为的阈值
你的CustomScrollBehaviourSample中用了75作为滚动阈值,但NavigationView的导航栏(含状态栏)默认高度约为92pt,数值不匹配会导致滚动计算偏差。把阈值改成92:struct CustomScrollBehaviourSample : ScrollTargetBehavior { func updateTarget(_ target: inout ScrollTarget, context: TargetContext) { // 用92替换原来的75,适配导航栏高度 if target.rect.minY < 92 { target.rect = .zero } } }简化"TOP NEWS"的frame设置
当前Text("TOP NEWS")的.frame(height:45)可能和上方间距叠加,试试移除这个frame设置,让文本高度自适应:Text("TOP NEWS") .font(.largeTitle.bold()) .padding(.horizontal,15) // 移除.frame(height: 45)
内容的提问来源于stack exchange,提问作者KARAN _186
相关产品推荐
相关产品推荐

