skip to Main Content

I want to make my code inside a scrollview based on a boolean

Something like this :

 ScrollView{
    
          Vstack {
                
         }
         
           Hstack {
           
            }
    
    }.isWrapped(true)

So if the bool is true, the content is wrapped inside a ScrollView, if not, I just get the content as is. (without the scrollView parent)

I tried with multiples way, the only thing I see as possible is 2 blocks of code, not good practice thought.

3

Answers


  1. Because of the nature of SwiftUI, you can’t remove the parent without removing children. As you mentioned in your edit, this will require two blocks of code. But, you can make it much more friendly in two different ways.


    The first way is a reusable component. It takes a Binding isVisible variable and the content.

    struct ConditionalScrollView<Content: View>: View {
        @Binding private var isVisible: Bool
        private var builtContent: Content
    
        init(isVisible: Binding<Bool>, content: () -> Content) {
            self._isVisible = isVisible
            builtContent = content()
        }
    
        var body: some View {
            if isVisible {
                ScrollView { builtContent }
            } else {
                builtContent
            }
        }
    }
    

    To use this new component is to simply replace the use of ScrollView in the area that you want to manually adjust. I.E:

    struct ContentView: View {
        @State var isVisible = true
    
        var body: some View {
            ConditionalScrollView(isVisible: $isVisible) {
                Text("Hello, world!")
                    .padding()
            }
        }
    }
    

    But this is not your only option.


    If you want to keep things as simple as possible, you can achieve this using a simple ViewBuilder. Create the view you don’t want to change inside the ViewBuilder, and then create a condition around the ScrollView, all the while placing the variable as the content. It would look as follows:

    struct ContentView: View {
        @State private var isVisible = true
    
        @ViewBuilder private var mainContent: some View {
            Text("Hello, world!")
                .padding()
        }
    
        var body: some View {
            if isVisible {
                ScrollView { mainContent }
            } else {
                mainContent
            }
        }
    }
    

    As you’ve probably come to realize, this is one of the limitations of SwiftUI. But it can be considered a strength because you will always know if a view’s parent is there or not.

    I hope this little tidbit helped, happy coding!

    Login or Signup to reply.
  2. You can also make it even easier:

    @State var isWraped : bool = true
    
    var body: some View {
       if isWrapped {
         ScrollView {
              YourView()
         }
           else {
              YourView()
         }
    
    Login or Signup to reply.
  3. One way is to always use a ScrollView, but tell it not to scroll. If you pass an empty set as the first argument to ScrollView, it won’t scroll.

    ScrollView(shouldScroll ? .vertical : []) {
        // content here
    }
    

    Another way is to extract the content back out of the ScrollView in your proposed isWrapped modifier, like this:

    extension ScrollView {
        @ViewBuilder
        func isWrapped(_ flag: Bool) -> some View {
            if flag { self }
            else { self.content }
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search