Currently I have a view that looks like this.
struct StatsView: View {
var body: some View {
ScrollView {
Text("Test1")
Text("Test2")
Text("Test3")
}
}
}
This renders a view that contains 3 texts inside a scroll view, whenever I drag any of these texts in the screen the view will move cause its scrollable, even if these 3 texts fit in the screen and there is remaining space. What I want to achieve is to only make the ScrollView scrollable if its content exceeds the screen height size, if not, I want the view to be static and don't move. I've tried using GeometryReader and setting the scrollview frame to the screen width and height, also the same for the content but I continue to have the same behaviour, also I have tried setting the minHeight, maxHeight without any luck.
How can I achieve this?
For some reason I could not make work any of the above, but it did inspire me find a solution that did in my case. It's not as flexible as others, but could easily be adapted to support both axes of scrolling.
import SwiftUI
struct OverflowContentViewModifier: ViewModifier {
@State private var contentOverflow: Bool = false
func body(content: Content) -> some View {
GeometryReader { geometry in
content
.background(
GeometryReader { contentGeometry in
Color.clear.onAppear {
contentOverflow = contentGeometry.size.height > geometry.size.height
}
}
)
.wrappedInScrollView(when: contentOverflow)
}
}
}
extension View {
@ViewBuilder
func wrappedInScrollView(when condition: Bool) -> some View {
if condition {
ScrollView {
self
}
} else {
self
}
}
}
extension View {
func scrollOnOverflow() -> some View {
modifier(OverflowContentViewModifier())
}
}
Usage
VStack {
// Your content
}
.scrollOnOverflow()
Here is a possible approach if a content of scroll view does not require user interaction (as in PO question):
Tested with Xcode 11.4 / iOS 13.4
struct StatsView: View {
@State private var fitInScreen = false
var body: some View {
GeometryReader { gp in
ScrollView {
VStack { // container to calculate total height
Text("Test1")
Text("Test2")
Text("Test3")
//ForEach(0..<50) { _ in Text("Test") } // uncomment for test
}
.background(GeometryReader {
// calculate height by consumed background and store in
// view preference
Color.clear.preference(key: ViewHeightKey.self,
value: $0.frame(in: .local).size.height) })
}
.onPreferenceChange(ViewHeightKey.self) {
self.fitInScreen = $0 < gp.size.height // << here !!
}
.disabled(self.fitInScreen)
}
}
}
Note: ViewHeightKey
preference key is taken from this my solution
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With