33

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")
       ...
       ...
}
Rohit Makwana
  • 4,337
  • 1
  • 21
  • 29
  • 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. – Asperi Nov 11 '19 at 13:30
  • 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. – Rohit Makwana Nov 12 '19 at 05:17
  • 2
    Did you find any solution? – Sandeep Maurya Dec 06 '19 at 07:31
  • not able to find solution – Rohit Makwana Jan 06 '20 at 09:30
  • 2
    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](https://stackoverflow.com/a/62466397/12299030). It is not applicable for active content, because based on `.disabled` modifier. – Asperi Jun 19 '20 at 08:57

6 Answers6

35

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
 }
Anshuman Singh
  • 1,018
  • 15
  • 17
  • 13
    doesnt the first one change all scrollviews in my app too? – Di Nerd Apps May 29 '20 at 09:29
  • 1
    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. – Anshuman Singh Jun 01 '20 at 06:00
  • 3
    If you only want to disable bouncing if the content is smaller than the scrollview size, do this: `UIScrollView.appearance().alwaysBounceVertical = false` – Tamás Sengel Mar 05 '22 at 15:59
  • 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. – cbh2000 Mar 06 '23 at 19:18
9
  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
}
Goldmember
  • 101
  • 1
  • 3
7

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)
    }
}
PatrickDotStar
  • 1,654
  • 1
  • 19
  • 20
6

You may use SwiftUI-Introspect library:

ScrollView {
    // some content
}
.introspectScrollView { scrollView in
    scrollView.alwaysBounceVertical = false
}
General Failure
  • 2,421
  • 4
  • 23
  • 49
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()
            }
            
        }
    }  
 
LC 웃
  • 18,888
  • 9
  • 57
  • 72
  • Looks like the same behavior. It still bounced. – chitgoks Sep 10 '22 at 07:50
  • 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 @chitgoks issue as well. – Trev14 Mar 06 '23 at 05:58
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.

jakeo
  • 61
  • 4