How to disable scroll in SwiftUI 4 using scrollDisabled modifier.

DevTechie Inc
Dec 7, 2022


Photo by Taylor Wilcox on Unsplash

List or ScrollViews are probably some of the most used and useful views in the world of SwiftUI. These views makes it super easy to present a collection of data in a manageable, scrollable fashion.

But imagine a scenario where you want to present a view on top of these scrolling views but also want to make sure that user doesn’t lose the scroll position by mistake as the view in the back can still receive events. Something like this:

Notice that we are giving all visual clues to the user that view in the background is blurred meaning modal presented at the top is the main view but it doesn’t help much as user can still interact with the scrolling view.

Prior iOS 16 it was possible to disable scroll using simultaneousGesture modifier where we would do something like this:

.simultaneousGesture(DragGesture(minimumDistance: 0), including: .all)
This is a good approach but it disables all the DragGestures. Also, this approach has another issue, simultaneousGestureis not made for this it has a better purpose.

Starting iOS 16 and SwiftUI 4, we have a dedicated modifier which works on all scrolling views like ScrollViews, Lists even TextEditor. Modifier itself is called scrollDisabled(_:) and can directly be applied to the view.

So let’s say we have this view:

struct ScrollDisabledExample: View {
    
    @State private var showDetails = false
    
    var body: some View {
        NavigationStack {
            ZStack {
                List {
                    Text("Check out website for more!")
                        .font(.largeTitle)
                        .onTapGesture {
                            showDetails.toggle()
                        }
                    
                    ForEach(1..<50, id: \.self) { idx in
                        Label("Item \(idx)", systemImage: "\(idx).circle.fill")
                    }
                }
                .navigationTitle("DevTechie.com")
                .blur(radius: showDetails ? 5.0 : 0.0)
                
                if showDetails {
                    VStack {
                        Text("Check out www.DevTechie.com for more exciting courses")
                            .font(.title)
                        Button {
                            showDetails.toggle()
                        } label: {
                            Label("Close", systemImage: "xmark")
                                .foregroundColor(.primary)
                        }
                        .buttonStyle(.borderedProminent)}
                    .padding()
                    .frame(maxWidth: .infinity)
                    .background(.thinMaterial, in: RoundedRectangle(cornerRadius: 20))
                    
                }
            }
        }
    }
}
Let’s apply scrollDisabled modifier to the list to fix this issue:

struct ScrollDisabledExample: View {
    
    @State private var showDetails = false
    
    var body: some View {
        NavigationStack {
            ZStack {
                List {
                    Text("Check out website for more!")
                        .font(.largeTitle)
                        .onTapGesture {
                            showDetails.toggle()
                        }
                    
                    ForEach(1..<50, id: \.self) { idx in
                        Label("Item \(idx)", systemImage: "\(idx).circle.fill")
                    }
                }
                .navigationTitle("DevTechie.com")
                .scrollDisabled(showDetails)
                .blur(radius: showDetails ? 5.0 : 0.0)
                
                if showDetails {
                    VStack {
                        Text("Check out www.DevTechie.com for more exciting courses")
                            .font(.title)
                        Button {
                            showDetails.toggle()
                        } label: {
                            Label("Close", systemImage: "xmark")
                                .foregroundColor(.primary)
                        }
                        .buttonStyle(.borderedProminent)}
                    .padding()
                    .frame(maxWidth: .infinity)
                    .background(.thinMaterial, in: RoundedRectangle(cornerRadius: 20))
                    
                }
            }
        }
    }
}

Build and run:

With that we have reached the end of this article. Thank you once again for reading. Don’t forget to follow 😍. Also subscribe our newsletter at https://www.devtechie.com