Search code examples
if-statementswiftuiscrollviewviewbuilder

Custom Scrollview in SwiftUI


I have a piece of code that looks like this in my ContentView and I'd like to not repeat the ScrollView's modifiers unnecessarily.

if variable == false {
    ScrollView {
        // Code here
    }
    .navigationBarTitleDisplayMode(.inline)
    .toolbar() {
        // Code here
    }
} else {
    ScrollView(.horizontal, showsIndicators: false) {
        // Code here
    }
    .navigationBarTitleDisplayMode(.inline)
    .toolbar() {
        // Code here
    }

So I tried to do this instead:

ScrollView(variable ? .horizontal, showsIndicators: false : nil) {
    // Code here
}
.navigationBarTitleDisplayMode(.inline)
.toolbar() {
    // Code here
}

But it doesn't work. How do you guys do this kind of thing?

Maybe, I should create my own custom scrollview, but how ?

struct ScrollViewCustom /* What to write here? */ View {

    @AppStorage("variable") private var variable = false
    @ViewBuilder /* What to write here? */

    var body: some View {

        if variable == false {
            ScrollView()
        } else {
            ScrollView(.horizontal, showsIndicators: false)
        }
    }
}

Thanks in advance!


Solution

  • The ternary operator ? always needs two options (for true/false). So you can do:

    ScrollView(variable ? .horizontal : .vertical, showsIndicators: false)

    But keep in mind that inside the ScrollView you'll then need to switch between a VStack or HStack depending on Scroll direction.

    So actually your custom approach might be more useful. It goes like this:

    struct ScrollViewCustom<V: View>: View {
    
        @AppStorage("variable") private var variable = false
        @ViewBuilder var content: () -> V
    
        var body: some View {
    
            if variable == false {
                ScrollView(.vertical) {
                    VStack {
                        content()
                    }
                }
            } else {
                ScrollView(.horizontal, showsIndicators: false) {
                    HStack {
                        content()
                    }
                }
            }
        }
    }
    

    and it would be used like this:

    struct ContentView: View {
        
        @AppStorage("variable") private var variable = false
        
        var body: some View {
            NavigationStack {
                ScrollViewCustom {
                    ForEach(0..<6) { item in
                        Text("Item \(item)")
                    }
                }
                .navigationBarTitleDisplayMode(.inline)
                .toolbar() {
                    Button("Switch") { variable.toggle() }
                }
            }
        }
    }