在 SwiftUI 中创建 BaseView 类

Sha*_*anu 18 user-interface swift swiftui

最近开始使用 SwiftUI 学习/开发应用程序,并且构建 UI 组件似乎很容易。但是,在 SwiftUI 中努力创建 BaseView。我的想法是在 BaseView 中拥有通用的 UI 控件,如 background 、 navigation 等,并且只是将其他 SwiftUI 视图子类化以自动拥有基本组件。

sup*_*cio 26

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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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")
                }
            }
        )
    }
}
Run Code Online (Sandbox Code Playgroud)

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

考虑到所有 SwiftUI API,这可能是 Apple 首选的处理方式。让我们尝试以这种不同的方式设计上面的例子

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!")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这样你就可以BgView像使用 aVStackList or whatever.

3)要有一个共同的风格:创建一个视图修改器

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())
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这些只是示例,但通常您会发现自己使用上述设计风格之一来做事。

编辑:关于@functionBuilder(因此也是关于@ViewBuilder)的一个非常有用的链接https://blog.vihan.org/swift-function-builders/

  • 对于按钮,您可能需要查看 ButtonStyle 而不是 ViewModifier。ButtonStyle 类似于 ViewModifier,只不过它应用于按钮的内容而不是按钮本身。例如,在上面的示例中,添加的填充将不可单击。这篇博文更好地解释了它:https://alejandromp.com/blog/2019/06/09/playing-with-swiftui-buttons/ (2认同)