Creating BaseView class in SwiftUI

后端 未结 1 727
别跟我提以往
别跟我提以往 2021-02-04 06:28

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

相关标签:
1条回答
  • 2021-02-04 07:22

    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/

    0 讨论(0)
提交回复
热议问题