Search code examples
swiftswiftuiscrollview

Make ScrollView scrollable only if it exceeds the height of the window


Currently I have a view 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 inside of the window, the view will move because it's scrollable, even if these 3 texts fit in the window and there is remaining space.
What I want to achieve is to only make the ScrollView scrollable if its content exceeds the window's height. If not, I want the view to be static and not move.

I've tried to use GeometryReader and setting the scroll view's frame to the window width and height, also the same for the content but I continue to have the same behavior. I have also tried setting minHeight and maxHeight without any luck.


Solution

  • 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)              // for iOS <16
                //.scrollDisabled(self.fitInScreen)      // for iOS 16+
            }
        }
    }
    

    Note: ViewHeightKey preference key is taken from this my solution