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