I'm pretty new in development and in SwiftUI. I learned a little with the Paul Hudson courses and by my self and I began to develop my first app but I'm facing a little problem that I can't solve alone...
I have a view with some long text and I embed it in a scrollView. To show user there is a scrollable text I add this little arrow at the bottom on my Text but I want to show it only when the text is long enough to not show entirely without scrolling. And if it's showed i need it to disappear when the bottom of the scrollView is reached and reappear when the user scroll back on top...
I let you my code here :
VStack {
Text("Lorem ipsum in my TestView")
.font(.title)
.padding(.bottom, 20)
ScrollViewReader { proxy in
ScrollView {
Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed accumsan mi elementum metus eleifend fermentum. Vestibulum a ligula laoreet libero rhoncus pharetra. Vivamus ac erat non odio tempus iaculis. Phasellus tincidunt dapibus ultricies. Aliquam erat volutpat. Maecenas aliquam est felis. Etiam consectetur viverra velit. Phasellus ligula metus, congue quis est vel, fermentum euismod ligula. Nunc pulvinar luctus semper. Nunc non fringilla ligula. Morbi scelerisque, augue non tempus hendrerit, tellus lectus sagittis ex, nec volutpat mi lacus maximus elit.").padding()
Text("").padding(.bottom, 10)
.id("end")
}.frame(maxWidth: 300, maxHeight: 100)
.padding()
.background(.quaternary)
.clipShape(RoundedRectangle(cornerRadius: 10))
if showBottom {
Button{
withAnimation {
proxy.scrollTo("end")
showBottom.toggle()
}
} label: {
Image(systemName: "chevron.down.circle.fill")
}
}
}
And there is a screenshot and a video to show the problem :
Video : Screen record
I tried to get the scroll status with scrollViewReader to show and hide the button but didn't work.
CodePudding user response:
You can achieve this by using a GeometryReader
. Then you can create a custom coordinate space for your ScrollView
and observe changes to the GeometryReader
´s position in this coordinate space.
But for this to work you need to know the height of the ScrollView
itself. As you allredy put a frame on it I simply pulled this out to a local var.
This is how this would look in an example:
ScrollView {
Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed accumsan mi elementum metus eleifend fermentum. Vestibulum a ligula laoreet libero rhoncus pharetra. Vivamus ac erat non odio tempus iaculis. Phasellus tincidunt dapibus ultricies. Aliquam erat volutpat. Maecenas aliquam est felis. Etiam consectetur viverra velit. Phasellus ligula metus, congue quis est vel, fermentum euismod ligula. Nunc pulvinar luctus semper. Nunc non fringilla ligula. Morbi scelerisque, augue non tempus hendrerit, tellus lectus sagittis ex, nec volutpat mi lacus maximus elit.").padding()
Color.clear
// use a 0 frame so it does not influence the layout
.frame(height: 0)
// id for scrolling
.id("end")
// add this to determine the position of the scrollview
.background(
// add the GeometryReader to the background
GeometryReader{reader in
// add another clear color to be able to observe
// changes to geometry reader position
Color.clear
.onChange(of: reader.frame(in: .named("newSpace"))) { newValue in
withAnimation {
// if the first clear color y value is lower than the
// height of the ScrollView plus a certain
// threashold hide the button
showBottom = !(newValue.minY < scrollViewHeight 50)
}
}
})
}.frame(width: 300, height: scrollViewHeight)
.padding()
.background(.quaternary)
.clipShape(RoundedRectangle(cornerRadius: 10))
// add this to define a coordinate space for the scrollview
.coordinateSpace(name: "newSpace")