Disable Scroll Programmatically in SwiftUI

DevTechie Inc
Jun 24, 2022


Photo by Taylor Wilcox on Unsplash

Scrolling is probably one of the most commonly used gesture in the world, thanks to our smartphones and abundance of content available to scroll through 😃

Sometimes its necessary to disable this gesture, if you are wondering when, let’s take a scenario. You are scrolling through the list of articles(hopefully they are DevTechie articles on DevTechie.com 🤞) and you get a notification, you tap on notification to open it as popup. Would you like your background content to scroll if you make a scroll gesture while the popup is in the foreground? 🤔 In my case, the answer is no. I would rather have scroll disabled while popup is in the foreground and continue to scroll when popup disappears.

I think that’s a pretty good use-case to disable scrolling programmatically, so we will build just that in this article today.

Let’s open a portal to the future and see, what we will have by the end of this article:

We will start with a view which will have two tabs, one for ScrollView and the other for List as both support scrolling behavior.

We will also have a toggle which will control the scroll behavior, we will start by making toggle false so user can scroll through the content.

Here is how our code will look,

struct DisableScrollProgrammatically: View {
    @State private var disableScroll = false
    var body: some View {
        NavigationView {
            VStack {
                Toggle("Disable Scroll", isOn: $disableScroll)
                
                TabView {
                    ScrollView {
                        VStack(spacing: 20) {
                            ForEach(1..<10) { idx in
                                Text("DevTechie Course \(idx)")
                            }
                        }
                    }
                    .tabItem {
                        Label("Scroll View", systemImage: "scroll.fill")
                    }
                    
                    List(1..<10) { idx in
                        Text("DevTechie Course \(idx)")
                    }
                    .tabItem {
                        Label("List View", systemImage: "list.bullet.rectangle.portrait.fill")
                    }
                }
            }
            .padding()
            .navigationTitle("DevTechie.com")
        }
    }
}
Next, we will create a custom ViewModifier which will take disabled as an input indicating if scroll should be disabled or not. We will use SimultaneousGesture and DragGesture to disable scrolling. We will set DragGesture’s minimum distance to 0, which will disable the drag gesture to stop the scroll behavior.

struct DisableScrolling: ViewModifier {
    var disabled: Bool
    
    func body(content: Content) -> some View {
    
        if disabled {
            content
                .simultaneousGesture(DragGesture(minimumDistance: 0))
        } else {
            content
        }
        
    }
}
Let’s also create an extension to this in View.

extension View {
    func disableScrolling(disabled: Bool) -> some View {
        modifier(DisableScrolling(disabled: disabled))
    }
}
Now is the time to add our new view modifier and our complete code will look like this:

struct DisableScrollProgrammatically: View {
    @State private var disableScroll = false
    var body: some View {
        VStack {
            Toggle("Disable Scroll", isOn: $disableScroll)
            
            TabView {
                ScrollView {
                    VStack(spacing: 20) {
                        ForEach(1..<10) { idx in
                            Text("DevTechie Course \(idx)")
                        }
                    }
                }
                .disableScrolling(disabled: disableScroll)
                .tabItem {
                    Label("Scroll View", systemImage: "scroll.fill")
                }
                
                List(1..<10) { idx in
                    Text("DevTechie Course \(idx)")
                }
                .disableScrolling(disabled: disableScroll)
                .tabItem {
                    Label("List View", systemImage: "list.bullet.rectangle.portrait.fill")
                }
            }
        }
    }
}struct DisableScrolling: ViewModifier {
    var disabled: Bool
    
    func body(content: Content) -> some View {
    
        if disabled {
            content
                .simultaneousGesture(DragGesture(minimumDistance: 0), including: .all)
        } else {
            content
        }
        
    }
}extension View {
    func disableScrolling(disabled: Bool) -> some View {
        modifier(DisableScrolling(disabled: disabled))
    }
}
Final output:



With that we have reached the end of this article. Thank you once again for reading. Subscribe to our weekly newsletter at https://www.devtechie.com