How to disable ScrollView Bounce In SwiftUI
Asked Answered
S

8

42

Any Modifier available to stop bounce of ScrollView in swiftUI ?

struct RoomDetailsView: View {

    var body: some View {
        ScrollView(showsIndicators: false) {
            Image("test")
            Text("Hello Text")
            ...
            ...
        }
    }
}

I tried below code but it not work for me. looks like it deprecated

ScrollView(alwaysBounceVertical: true) {
       Image("test")
       Text("Hello Text")
       ...
       ...
}
Symposium answered 11/11, 2019 at 10:19 Comment(5)
hmm.. I don't observe any bounce in the described scenario. So do you want to "stop" or to "add", because in second block of code it seems you try to enable it, however in question to disable it.Neu
I want to stop bounce in scrollview. earlier second block is working. but now I'm not found right now any solution for that my current code is looks like first block.Symposium
Did you find any solution?Etesian
not able to find solutionSymposium
For the case of static content inside ScrollView it can be used solution from SwiftUI: Make ScrollView scrollable only if it exceeds the height of the screen. It is not applicable for active content, because based on .disabled modifier.Neu
C
42

try using this line of code:

UIScrollView.appearance().bounces = false

You can use it like this:-

struct RoomDetailsView: View {
   init() {
      UIScrollView.appearance().bounces = false
   }

   var body: some View {
      ScrollView(showsIndicators: false) {
         Image("test")
         Text("Hello Text")
         ...
         ...
          }
      }
  }

Or you can write this line in AppDelegate to apply this behaviour throughout into your app.

 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    UIScrollView.appearance().bounces = false
 }
Conch answered 24/1, 2020 at 13:52 Comment(4)
doesnt the first one change all scrollviews in my app too?Strander
Yup, @DiNerd the first will eventually change the appearance throughout the application, and this is the actual statement, below ones are just its implementation example. You can use any of the below two ways to achieve it.Conch
If you only want to disable bouncing if the content is smaller than the scrollview size, do this: UIScrollView.appearance().alwaysBounceVertical = falseDeodorant
WARNING: This caused bugs with our UIPageViewControllers. Apparently, they need bounces = true to work properly. Make sure you put it back to true to avoid breaking that class.Benbena
O
15
  1. Set the ScrollView's showsIndicators parameter equal to false so the user interacting with your view doesn't activate the scroll indicator (it can happen even without scrolling enabled).
ScrollView(showsIndicators: false)
  1. In the onAppear modifier for the ScrollView, add this line.
UIScrollView.appearance().bounces = false
  1. In the onDisappear modifier for the ScrollView, add this line.
UIScrollView.appearance().bounces = true

If you set UIScrollView.appearance().bounces equal to false in the init, it will prevent all of your app's ScrollViews from bouncing. By setting it equal to true in the onAppear modifier and equal to false in the onDisappear modifier, you ensure that it only effects the one ScrollView.

Your ScrollView should look something like this.

ScrollView(showsIndicators: false) {
    ...
    ...
    ...
}
.onAppear {
    UIScrollView.appearance().bounces = false
}
.onDisappear {
    UIScrollView.appearance().bounces = true
}
Oligarchy answered 28/9, 2022 at 21:40 Comment(1)
it will take effect it's child view. I have nested scrollview and only parent view need to be forbidden bouncing, anyone can help? on iOS 15Ladylike
K
14

Apple introduced an new modifier named scrollBounceBehavior with iOS 16.4 that can be used to prevent the ScrollView from bouncing when the content is smaller than the screen.

https://developer.apple.com/documentation/swiftui/view/scrollbouncebehavior(_:axes:)

struct RoomDetailsView: View {

    var body: some View {
        ScrollView(showsIndicators: false) {
            Image("test")
            Text("Hello Text")
            ...
            ...
        }
        .scrollBounceBehavior(.basedOnSize)
    }
}
Kassandra answered 20/2, 2023 at 9:43 Comment(4)
Almost there... Now we just need a way to disable it, unconditionally.Benbena
Nice answer! SwiftUI getting better and better.Tingaling
Honestly do not understand the SwiftUI team sometimes..Kaolinite
Apple has spoken, thou shall not not bounceAlula
N
7

You may use SwiftUI-Introspect library:

ScrollView {
    // some content
}
.introspectScrollView { scrollView in
    scrollView.alwaysBounceVertical = false
}
Nursery answered 29/7, 2021 at 12:2 Comment(4)
Tried this now. Already added the library. Value of type 'ScrollView<some View>' has no member 'introspectScrollView'Postexilian
did you add import? "import Introspect"Arcade
Doesn't work for me :(Sharasharai
replace "scrollView.alwaysBounceVertical = false" with -> "scrollView.bounces = false"Anni
O
2

I have created a small ViewModifier in order to disable scrolling bounces only in specific Views:

import SwiftUI

extension View {
  func disableBounces() -> some View {
    modifier(DisableBouncesModifier())
  }
}

struct DisableBouncesModifier: ViewModifier {
  func body(content: Content) -> some View {
    content
      .onAppear {
        UIScrollView.appearance().bounces = false
      }
      .onDisappear {
        UIScrollView.appearance().bounces = true
      }
  }
}

Then you can simply call it on your views as any normal viewModifier

// Your view definition... 
.disableBounces()
Only answered 31/10, 2023 at 12:13 Comment(0)
P
1

A better solution would be to use viewbuilder and create your own scrollview that doesn't bounce when the content size is less than scrollview frame size.

import SwiftUI

struct BounceVerticalDisableScrollView<Content: View>: View {
    
    @State private var alwaysBounceVertical = false
    let content: Content
    
    init(@ViewBuilder content: () -> Content) {
        self.content = content()
    }
    
    var body: some View {
        GeometryReader { scrlViewGeometry in
            ScrollView {
                content
                    .background(
                        GeometryReader {
                            // calculate height by clear background
                            Color.clear.preference(key: SizePreferenceKey.self,
                                                   value: $0.frame(in: .local).size.height)
                        }.onPreferenceChange(SizePreferenceKey.self) {
                            self.alwaysBounceVertical = $0 < scrlViewGeometry.size.height
                        }
                    )
            }
            // disable scroll when content size is less than frame of scrollview
            .disabled(self.alwaysBounceVertical)
        }
    }
}
// return size
public struct SizePreferenceKey: PreferenceKey {
    public static var defaultValue: CGFloat = .zero
    
    public static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
        value += nextValue()
    }
}

So, that you can use the scrollview as:

var body: some View {
        VStack (alignment: .leading, spacing: 10) {
            BounceVerticalDisableScrollView{
                VStack (alignment: .leading, spacing: 10)  {
                   ....
                   .... 
                }.padding()
            }
            
        }
    }  
 
Profitsharing answered 15/6, 2022 at 8:42 Comment(2)
Looks like the same behavior. It still bounced.Postexilian
I think you may want to just return nextValue() in the size preference reduce function right? If you add it to the existing value then it's going to keep getting bigger with every layout change, rather than simply reflecting the most recent content height. I'm assuming that's what caused @Postexilian issue as well.Tingaling
G
0

Honestly, the available options aren't great as they aren't backwards compatible and tend to completely disable scrolling.

A workaround is to add height to your scrollview.

Gaussmeter answered 15/6, 2023 at 0:6 Comment(0)
S
0

To disable bounce of scroll view in swift ui, You can use

 .onAppear {
                 UIScrollView.appearance(whenContainedInInstancesOf: [UIHostingController<SwiftUIView>.self]).bounces = false
             }

This disables the bounce behaviour only in a particular swift ui view.

Subrogate answered 28/5 at 20:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.