Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating BaseView class in SwiftUI

Lately started learning/developing apps with SwiftUI and seems pretty easy to build the UI components. However, struggling creating a BaseView in SwiftUI. My idea is to have the common UI controls like background , navigation , etc in BaseView and just subclass other SwiftUI views to have the base components automatically.

like image 917
Shantanu Avatar asked Aug 28 '19 06:08

Shantanu


2 Answers

Usually you want to either have a common behaviour or a common style.

1) To have a common behaviour: composition with generics

Let's say we need to create a BgView which is a View with a full screen image as background. We want to reuse BgView whenever we want. You can design this situation this way:

struct BgView<Content>: View where Content: View {
    private let bgImage = Image.init(systemName: "m.circle.fill")
    let content: Content

    var body : some View {
        ZStack {
            bgImage
                .resizable()
                .opacity(0.2)
            content
        }
    }
}

You can use BgView wherever you need it and you can pass it all the content you want.

//1
struct ContentView: View {
    var body: some View {
        BgView(content: Text("Hello!"))
    }
}

//2
struct ContentView: View {
    var body: some View {
        BgView(content:
            VStack {
                Text("Hello!")
                Button(action: {
                    print("Clicked")
                }) {
                    Text("Click me")
                }
            }
        )
    }
}

2) To have a common behaviour: composition with @ViewBuilder closures

This is probably the Apple preferred way to do things considering all the SwiftUI APIs. Let's try to design the example above in this different way

struct BgView<Content>: View where Content: View {
    private let bgImage = Image.init(systemName: "m.circle.fill")
    private let content: Content

    public init(@ViewBuilder content: () -> Content) {
        self.content = content()
    }

    var body : some View {
        ZStack {
            bgImage
                .resizable()
                .opacity(0.2)
            content
        }
    }
}

struct ContentView: View {
    var body: some View {
        BgView {
            Text("Hello!")
        }
    }
}

This way you can use BgView the same way you use a VStack or List or whatever.

3) To have a common style: create a view modifier

struct MyButtonStyle: ViewModifier {
    func body(content: Content) -> some View {
        content
            .padding()
            .background(Color.red)
            .foregroundColor(Color.white)
            .font(.largeTitle)
            .cornerRadius(10)
            .shadow(radius: 3)
    }
}

struct ContentView: View {
    var body: some View {
        VStack(spacing: 20) {
            Button(action: {
                print("Button1 clicked")
            }) {
                Text("Button 1")
            }
            .modifier(MyButtonStyle())

            Button(action: {
                print("Button2 clicked")
            }) {
                Text("Button 2")
            }
            .modifier(MyButtonStyle())

            Button(action: {
                print("Button3 clicked")
            }) {
                Text("Button 3")
            }
            .modifier(MyButtonStyle())
        }
    }
}

These are just examples but usually you'll find yourself using one of the above design styles to do things.

EDIT: a very useful link about @functionBuilder (and therefore about @ViewBuilder) https://blog.vihan.org/swift-function-builders/

like image 143
matteopuc Avatar answered Oct 14 '22 08:10

matteopuc


I got a idea about how to create a BaseView in SwiftUI for common usage in other screen

By the way Step .1 create ViewModifier

struct BaseScene: ViewModifier {
    
    /// Scene Title
    var screenTitle: String
    
    func body(content: Content) -> some View {
        VStack {
            HStack {
                Spacer()
                Text(screenTitle)
                    .font(.title)
                    .foregroundColor(.white)
                Spacer()
            }.padding()
            .background(Color.blue.opacity(0.8))
            content
        }
    }
}

Step .2 Use that ViewModifer in View

struct BaseSceneView: View {
    
    var body: some View {
        
        VStack {
            Spacer()
            Text("Home screen")
                .font(.title)
            Spacer()
        }
        .modifier(BaseScene(screenTitle: "Screen Title"))
    }
}

struct BaseSceneView_Previews: PreviewProvider {
    static var previews: some View {
        Group {
            BaseSceneView()
        }
    }
}

Your Output be like:

BaseView screen example

like image 34
Kathiresan Murugan Avatar answered Oct 14 '22 08:10

Kathiresan Murugan