如何防止我的SwiftUI视图在滚动时调整大小

如何防止我的SwiftUI视图在滚动时调整大小,swift,swiftui,scrollview,geometryreader,Swift,Swiftui,Scrollview,Geometryreader,我希望有人能给我指出正确的方向——我一直在试验SwiftUI,我创建了一个与Twitter个人资料UI有点类似的视图 我似乎有一个奇怪的效果时,标题崩溃 有一个“最佳点”,在滚动视图包含在标题下滚动之前,标题被折叠,选项卡栏的大小被稍微调整 你可以从中看到 我根本不想调整选项卡段的大小,相反,它应该在页眉折叠后保持原位,滚动视图应该在其下方自由移动 我肯定我错过了一些明显的东西,但是一些新鲜的眼睛可能正是我需要的帮助 如果您对此有任何想法,我们将不胜感激 import SwiftUI stru

我希望有人能给我指出正确的方向——我一直在试验SwiftUI,我创建了一个与Twitter个人资料UI有点类似的视图

我似乎有一个奇怪的效果时,标题崩溃

有一个“最佳点”,在滚动视图包含在标题下滚动之前,标题被折叠,选项卡栏的大小被稍微调整

你可以从中看到

我根本不想调整选项卡段的大小,相反,它应该在页眉折叠后保持原位,滚动视图应该在其下方自由移动

我肯定我错过了一些明显的东西,但是一些新鲜的眼睛可能正是我需要的帮助

如果您对此有任何想法,我们将不胜感激

import SwiftUI

struct ContentView: View {
    
    @State private var safeArea: EdgeInsets = EdgeInsets(.zero)
    @State private var offset: CGFloat = 0
    @State private var tabBarOffset: CGFloat = 0
    
    @State var currentTab = "Tab #1"
    @Namespace var animation
    
    var body: some View {
        GeometryReader { foo in
            ScrollView {
                VStack(spacing: 0) {
                    // Header
                    GeometryReader { proxy -> AnyView in
                        // Sticky Header
                        DispatchQueue.main.async {
                            offset = proxy.frame(in: .global).minY
                            safeArea = foo.safeAreaInsets
                        }
                        
                        return AnyView(makeHeader())
                    }
                    .frame(height: 180)
                    .zIndex(1)
                    
                    // Profile
                    VStack(spacing: 0) {
                        VStack(spacing: 0) {
                            HStack(spacing: 0) {
                                TabButton(title: "Tab #1", currentTab: $currentTab, animation: animation)
                                    .frame(maxWidth: .infinity)
                                TabButton(title: "Tab #2", currentTab: $currentTab, animation: animation)
                                    .frame(maxWidth: .infinity)
                                TabButton(title: "Tab #3", currentTab: $currentTab, animation: animation)
                                    .frame(maxWidth: .infinity)
                            }
                            Divider()
                        }
                        .padding(.top, 20)
                        .background(Color.white)
                        .offset(y: tabBarOffset < 90 ? -tabBarOffset + 90 : 0)
                        .overlay(
                            GeometryReader { proxy -> Color in
                                DispatchQueue.main.async {
                                    tabBarOffset = proxy.frame(in: .global).minY
                                }
                                return Color.clear
                            }
                            .frame(width: 0, height: 0),
                            alignment: .top
                        )
                        .zIndex(1)
                        VStack {
                            ForEach((0..<50)) {
                                Text("Row #\($0)")
                                Divider()
                            }
                        }
                        .padding(.top)
                        .zIndex(0)
                    }
                }
            }
            .ignoresSafeArea(.all, edges: .top)
        }
    }
    
    @ViewBuilder func makeHeader() -> some View {
        ZStack {
            // Cover
            Color.gray
                .frame(maxWidth: .infinity)
                .frame(height: offset > 0 ? 180 + offset : 180)
        }
        .clipped()
        // Stretchy Effect
        .frame(height: offset > 0 ? 180 + offset : nil)
        .offset(y: offset > 0 ? -offset : -offset < 80 ? 0 : -offset - 80)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

struct TabButton: View {
    var title: String
    @Binding var currentTab: String
    var animation: Namespace.ID
    
    var body: some View {
        Button(
            action: {
                withAnimation { currentTab = title }
            },
            label: {
                LazyVStack(spacing: 12) {
                    Text(title)
                        .fontWeight(.semibold)
                        .foregroundColor(currentTab == title ? .blue : .gray)
                        .padding(.horizontal)
                    
                    if currentTab == title {
                        Capsule()
                            .fill(Color.blue)
                            .frame(height: 1.2)
                            .matchedGeometryEffect(id: "TAB", in: animation)
                    } else {
                        Capsule()
                            .fill(Color.clear)
                            .frame(height: 1.2)
                    }
                    
                }
            }
        )
    }
}
导入快捷界面
结构ContentView:View{
@国家私有var安全区域:EdgeInsets=EdgeInsets(.0)
@国家私有变量偏移量:CGFloat=0
@国家私有var TABBOROFFSET:CGFloat=0
@State var currentTab=“Tab#1”
@名称空间变量动画
var body:一些观点{
GeometryReader{foo-in
滚动视图{
VStack(间距:0){
//标题
GeometryReader{proxy->AnyView中的
//粘头
DispatchQueue.main.async{
offset=proxy.frame(in:.全局).minY
safeArea=foo.safeArea插图
}
返回AnyView(makeHeader())
}
.框架(高度:180)
.zIndex(1)
//侧面图
VStack(间距:0){
VStack(间距:0){
HStack(间距:0){
TabButton(标题:“Tab#1”,currentTab:$currentTab,动画:动画)
.frame(最大宽度:。无穷大)
TabButton(标题:“Tab#2”,currentTab:$currentTab,动画:动画)
.frame(最大宽度:。无穷大)
TabButton(标题:“Tab#3”,currentTab:$currentTab,动画:动画)
.frame(最大宽度:。无穷大)
}
分隔器()
}
.padding(.top,20)
.背景(颜色.白色)
.偏移量(y:tabBarOffset<90?-tabBarOffset+90:0)
.覆盖(
GeometryReader{proxy->Color in
DispatchQueue.main.async{
tabBarOffset=proxy.frame(在:.global.minY中)
}
返回颜色。清除
}
.框架(宽度:0,高度:0),
对齐:。顶部
)
.zIndex(1)
VStack{
ForEach((0..some视图{
ZStack{
//掩护
颜色:灰色
.frame(最大宽度:。无穷大)
.帧(高度:偏移>0?180+偏移:180)
}
.clipped()
//拉伸效应
.帧(高度:偏移>0?180+偏移:零)
.偏移量(y:偏移量>0?-偏移量:-偏移量<80?0:-偏移量-80)
}
}
结构内容视图\u预览:PreviewProvider{
静态var预览:一些视图{
ContentView()
}
}
结构选项卡按钮:视图{
变量标题:字符串
@绑定变量currentTab:字符串
var动画:Namespace.ID
var body:一些观点{
钮扣(
行动:{
withAnimation{currentTab=title}
},
标签:{
LazyVStack(间距:12){
正文(标题)
.fontWeight(.半加粗)
.foregroundColor(currentTab==标题?.blue:.灰色)
.padding(.卧式)
如果currentTab==标题{
胶囊()
.填充(颜色.蓝色)
.框架(高度:1.2)
.matchedGeometryEffect(id:“选项卡”,在:动画中)
}否则{
胶囊()
.填充(颜色.透明)
.框架(高度:1.2)
}
}
}
)
}
}

在这里,将设置为90而不是80。作为设置顶部的选项卡栏视图,y偏移量为90,整个逻辑基于90值

@ViewBuilder func makeHeader() -> some View {
    ZStack {
        // Cover
        Color.red
            .frame(maxWidth: .infinity)
            .frame(height: offset > 0 ? 180 + offset : 180)
    }
    .clipped()
    // Stretchy Effect
    .frame(height: offset > 0 ? 180 + offset : nil)
    .offset(y: offset > 0 ? -offset : -offset < 90 ? 0 : -offset - 90) //<=== Here
}
@ViewBuilder func makeHeader()->一些视图{
ZStack{
//掩护
颜色:红色
.frame(最大宽度:。无穷大)
.帧(高度:偏移>0?180+偏移:180)
}
.clipped()
//拉伸效应
.帧(高度:偏移>0?180+偏移:零)
.偏移量(y:偏移量>0?-偏移量:-偏移量<90?0:-偏移量-90)//