将视图提取到函数或结构?

时间:2021-07-15 08:57:49

标签: swift swiftui

我是学习 Swift 和 SwiftUI 的新手。我有一个包含 VStack 的视图结构。在 VStack 中,我调用了四个返回视图的函数。

var body: some View {
    VStack {
        
        self.renderLogo()
        self.renderUserNameTextField()
        self.renderPasswordSecureField()
        self.renderLoginButton()
        
    }
}

func renderLoginButton() -> some View {
    return Button(action: {print("Button clicked")}){
        Text("LOGIN").font(.headline).foregroundColor(.white).padding().frame(width: 220, height: 60).background(Color(red: 0, green: 70/255, blue: 128/255)).cornerRadius(15.0)
    }.padding()
}[...]

我刚刚读到,将视图提取到这样的结构中更为常见:

struct UsernameTextField : View {
@Binding var username: String
var body: some View {
return TextField("Username", text: $username)
            .padding()
            .background(lightGreyColor)
            .cornerRadius(5.0)
            .padding(.bottom, 20)
    }
}

这是为什么?使用结构体代替普通函数有什么优势?

3 个答案:

答案 0 :(得分:2)

如果该视图与主视图至少有一个 @Binding,我会在不同的结构中分离视图。否则,我会坚持功能。但是...

如果您想在单独的结构或函数中执行此操作取决于您,但要考虑到如果您想重用视图,如果将其声明为单独的视图会更容易实体。

这样做的另一个目的是避免在 SwiftUI 中拥有庞大的视图,将职责分离成更小的视图,使代码更易于阅读。

答案 1 :(得分:2)

这提出了一个有趣的观点。您不想通过使用带有大量修饰符的标准控件来制作大型视图,但您想要某种形式的重用,无论是通过使用函数返回视图还是自定义视图。

当我在 SwiftUI 中遇到这些问题时,我会查看我正在提取的内容。在您的情况下,控件看起来是标准的,但它们应用了不同的样式。线索在于函数名中都有 render

在这种情况下,我不会使用函数或自定义视图,而是编写一个自定义修饰符,将一组通用样式应用于控件。代码中的几个示例:

首先,创建 ViewModifiers

struct InputTextFieldModifier: ViewModifier {
    func body(content: Content) -> some View {
        content
            .padding()
            .background(Color.gray)
            .cornerRadius(5.0)
            .padding(.bottom, 20)
    }
}


struct ButtonTextModifier: ViewModifier {
    func body(content: Content) -> some View {
        content
            .font(.headline)
            .foregroundColor(.white)
            .padding()
            .frame(width: 220, height: 60)
            .background(Color(red: 0, green: 70/255, blue: 128/255))
            .cornerRadius(15.0)
    }
}

这些写起来很简单。您只需将所需的修饰符应用于内容参数即可。

为了使它们更易于使用,您可以将扩展名写入 View

extension View {
    func inputTextFieldStyle() -> some View {
        modifier(InputTextFieldModifier())
    }

    func buttonTextStyle() -> some View {
        modifier(ButtonTextModifier())
    }
}

这使得呼叫站点看起来像这样:

var body: some View {
    VStack {
        
        ...
        TextField(...)
            .inputTextFieldStyle()
        ...
        Button(action: {print("Button clicked")}){
            Text("LOGIN")
                .buttonTextStyle()
        }.padding()
        
    }
}

如果您希望能够配置修改器,那也很容易。假设要指定常用文本字段的背景颜色,可以重新编写修饰符以将其作为参数:

struct InputTextFieldModifier: ViewModifier {
    let backgroundColor: Color

    func body(content: Content) -> some View {
        content
            .padding()
            .background(backgroundColor)
            .cornerRadius(5.0)
            .padding(.bottom, 20)
    }
}

并更新您的便利函数以将其作为参数:

extension View {
    func inputTextFieldStyle(backgroundColor: Color) -> some View {
        modifier(InputTextFieldModifier(backgroundColor: backgroundColor))
    }
}

在呼叫站点:

TextField("Username", text: $username)
    .inputTextFieldStyle(backgroundColor: Color.gray)

并且自定义修饰符是可重复使用的。

答案 2 :(得分:1)

更建议将您的 views 提取到 structs,这样您以后可以在代码中重用您的视图,使您的代码更加干净和隔离。