我正在尝试创建一个自定义滚动视图,如果用户滚动到末尾,它可以通知父视图。
这就是我的实现方式:
struct CustomVerticalScrollView<Content: View>: View {
let content: Content
init(@ViewBuilder content: () -> Content) {
self.content = content()
}
var body: some View {
ScrollView {
content
Color
.clear
.frame(width: 0, height: 0)
.modifier(ViewAppearsOnScreen())
.onPreferenceChange(IsOnScreenKey.self) { value in
if value == true {
print("Has reached end!")
}
}
}
.background(.green)
}
}
struct ViewAppearsOnScreen: ViewModifier {
func body(content: Content) -> some View {
GeometryReader { geometry in
// Check if this view's frame intersects with the visible screen bounds
content
.preference(
key: IsOnScreenKey.self,
value: isViewVisible(geometry: geometry)
)
}
}
// Determines if the view is visible within the screen's bounds
private func isViewVisible(geometry: GeometryProxy) -> Bool {
let frame = geometry.frame(in: .global) // Get the frame in global space
let screenBounds = UIScreen.main.bounds // Screen boundaries
return screenBounds.intersects(frame) // Check if it intersects with screen bounds
}
}
此处用于检测滚动视图结束的代码取自此answer
然后这就是我的使用方式:
struct ContentView: View {
var body: some View {
CustomVerticalScrollView{
VStack(spacing: .zero) {
Color
.blue
.frame(maxWidth: .infinity)
.frame(height: 1000)
}
}
}
}
该功能运行良好,但是,这给了我以下带有一些额外间距的结果:
虽然将高度设置为 0 并使用几何读取器不会影响间距。
只是想知道如何消除所有这些额外的间距,以便我可以在其中获得额外的视图。
GeometryReader
会将自身调整到理想高度,该高度恰好是一个小的非零值。您可以将 frame(width: 0, height: 0)
移至 onPreferenceChange
之后来修复此问题。
每个 SwiftUI 视图在所有四个边缘上都有自己的“首选间距”,并且此间距可能会根据其他视图的类型而有所不同。例如,
Text
和 Image
之间的首选间距比两个 Text
之间的首选间距稍大。默认布局行为遵循此间距首选项。在实现您自己的 Layout
时,您可以使用 LayoutSubview.spacing
读取此首选间距。
使用带有显式
VStack
参数的 spacing:
会使 VStack
布局不尊重间距首选项。
ScrollView {
VStack(spacing: 0) {
content
Color
.clear
.modifier(ViewAppearsOnScreen())
.onPreferenceChange(IsOnScreenKey.self) { ... }
.frame(width: 0, height: 0)
}
}