I have created a horizontal carousel using a ScrollView
with an HStack
.
This is my code:
struct CarouselView<Content: View>: View {
let content: Content
private let spacing: CGFloat
private let shouldSnap: Bool
init(spacing: CGFloat = .zero,
shouldSnap: Bool = false,
@ViewBuilder content: @escaping () -> Content) {
self.content = content()
self.spacing = spacing
self.shouldSnap = shouldSnap
}
var body: some View {
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: spacing) {
content
}.apply {
if #available(iOS 17.0, *), shouldSnap {
$0.scrollTargetLayout()
} else {
$0
}
}
}
.clipped()
.apply {
if #available(iOS 17.0, *), shouldSnap {
$0.scrollTargetBehavior(.viewAligned)
} else {
$0
}
}
}
}
I then can use it as follows:
CarouselView(spacing: 10) {
ForEach(0 ..< imagesNames.count, id: .self) { index in
DemoView()
}
}
How can I detect when the user has scrolled to the end of the scroll view.
I’ve tried the some answers here – the main one of adding a view at the end of the hstack and doing the work on the onAppear
of that view does not work as it is fired immediately as the HStack is created.
This could work if I used a LazyHStack
– however, I have to use an HStack due to some limitations.
Are there any other ways to achieve this ?
2
Answers
You can use this
DetectOnScreen
view modifier I wrote in this answer to detect whether an invisible view is on screen.Usage:
This does mean the
HStack
will have on extra view, so there will be some extra space (of sizespacing
) between the last view and the invisible view. If this is undesirable, you can wrap the last view in its ownHStack
and put the invisible view in the innerHStack
. But this needs to be done at the use-site.Of if you don’t mind using View Extractor, you can do this in
CarouselView
You could try this approach using a simple
.scrollPosition(id: $scrolledID)
, to detect when the user has scrolled to the end of the scroll view.Example code: