简体   繁体   中英

Conditionally wrap code inside view SwiftUI

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.

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. IE:

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!

You can also make it even easier:

@State var isWraped : bool = true

var body: some View {
   if isWrapped {
     ScrollView {
          YourView()
     }
       else {
          YourView()
     }

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 }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM