Я пытаюсь создать собственное представление прокрутки, которое может уведомлять родительское представление, если пользователь прокрутил до конца.
Вот как я это реализую:
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
}
}
Код, используемый здесь для определения конца прокрутки, был взят из этого ответа
И вот как я его использую:
struct ContentView: View {
var body: some View {
CustomVerticalScrollView{
VStack(spacing: .zero) {
Color
.blue
.frame(maxWidth: .infinity)
.frame(height: 1000)
}
}
}
}
Однако эта функциональность работает хорошо. Это дает мне следующие результаты с некоторым дополнительным интервалом:
Хотя я установил высоту на 0 и использовал программу чтения геометрии, это не повлияет на интервал.
Просто интересно, как я могу устранить все эти дополнительные пробелы, чтобы у меня был дополнительный вид.
Кажется, это действительно работает @Sweeper. Я немного понимаю, как добавить кадр после всех модификаторов, но не понимаю, зачем нам нужен VStack с нулевым интервалом. Кажется, что между элементами в режиме прокрутки существует какое-то расстояние по умолчанию, которое мы не можем переопределить?
Да, действительно существует «некоторое расстояние по умолчанию между элементами в режиме прокрутки». На самом деле вы можете прочитать, насколько велик этот интервал, реализуя свой собственный Layout. См. LayoutSubview.spacing.





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)
}
}
Попробуйте поставить
frame(width: 0, height: 0)послеmodifierиonPreferenceChangeи окружитьcontentиColor.clearVStack(spacing: .zero), возможно?