我有一个带有 ScrollView 的 SwiftUI 视图,其构造如下:
ZStack(alignment: .top){
Color.black
VStack {
HeaderView()
ScrollView(.vertical) {
content
}
}
}
我想在用户在 ScrollView 上向下滚动时隐藏 HeaderView() ,但在用户向上滚动时显示它(最好有一点偏移),即使 ScrollView 没有滚动所有通往山顶的路。
这是在很多应用程序上完成的,包括 Artifact,它是这样做的:
使用 GeometryReadyer/ScrollViewReader 没有帮助/或者我没有正确实现它?
如果您将
GeometryReader
放置在滚动内容的背景中,则可以使用它来检测滚动位置的变化。当滚动方向改变时,可以使用 .onChange
处理程序来切换标题的可见性。
但是,为了防止滚动弹跳导致标题可见性在不应该的情况下切换,可以使用另一个
GeometryReader
来测量 ScrollView
的高度。然后,可以将位置的测量限制为内容的精确高度,从而忽略反弹。
这是对您的示例的改编,以显示其工作原理:
@State private var showingHeader = true
var body: some View {
VStack {
if showingHeader {
HeaderView()
.transition(
.asymmetric(
insertion: .push(from: .top),
removal: .push(from: .bottom)
)
)
}
GeometryReader { outer in
let outerHeight = outer.size.height
ScrollView(.vertical) {
content
.background {
GeometryReader { proxy in
let contentHeight = proxy.size.height
let minY = max(
min(0, proxy.frame(in: .named("ScrollView")).minY),
-(contentHeight - outerHeight)
)
Rectangle()
.fill(.clear)
.onChange(of: minY) { oldVal, newVal in
if (showingHeader && newVal < oldVal) || !showingHeader && newVal > oldVal {
showingHeader.toggle()
}
}
}
}
}
.coordinateSpace(name: "ScrollView")
}
// Prevent scrolling into the safe area
.padding(.top, 1)
}
.background(.black)
.animation(.easeInOut, value: showingHeader)
}