热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

SwiftUI:具有视图组成的代码重用

如何解决《SwiftUI:具有视图组成的代码重用》经验,为你挑选了1个好方法。

使用SwiftUI开发我发现很难重用组成视图的代码。我将向您展示一个简单的示例:假设我们的应用程序中有一个带有特定UI的文本字段。让我们将此文本字段称为MyTextField。用户界面可能是:

这是代码:

struct MyTextField: View {
    @Binding var text: String
    var label: String

    var body: some View {
        VStack {
            HStack {
                Text(label)
                Spacer()
            }
            TextField("", text: $text) //here we have a simple TextField
            Divider()
        }
        .padding()
    }
}

现在,假设我们要拥有另一个具有相同UI的文本字段,但要在安全上下文中使用。此文本字段称为MySecureTextField。在这种情况下,我应该使用SecureField而不是TextField,但是显然我不想以这种方式创建一个全新的视图:

struct MySecureTextField: View {
    @Binding var text: String
    var label: String

    var body: some View {
        VStack {
            HStack {
                Text(label)
                Spacer()
            }
            SecureField("", text: $text) //this time we have a SecureField here
            Divider()
        }
        .padding()
    }
}

我该如何设计这样的情况?我尝试了几种方法,但似乎没有一种是正确的:

1-第一次尝试拥有某种以实际文本字段为参数的容器视图:

struct TextFieldContainer: View where ActualTextField: View {
    private let actualTextField: () -> ActualTextField
    var label: String

    init(label: String, @ViewBuilder actualTextField: @escaping () -> ActualTextField) {
        self.label = label
        self.actualTextField = actualTextField
    }

    var body: some View {
        VStack {
            HStack {
                Text(label)
                Spacer()
            }
            actualTextField()
            Divider()
        }
        .padding()
    }
}

我可以用TextFieldContainer这种方式:

struct ContentView: View {
    @State private var text = ""

    var body: some View {
        TextFieldContainer(label: "Label") {
            SecureField("", text: self.$text)
        }
    }
}

我不喜欢这种解决方案:我不想指定实际的文本字段,它应该隐含在视图本身(MyTextFieldMySecureTextField)中。这样,我什至可以在容器内注入任何类型的视图,而不仅仅是文本字段。

2-第二次尝试拥有一个私有容器和两个在内部使用该容器的公共视图:

private struct TextFieldContainer: View where ActualTextField: View {
    //...
    //the same implementation as above
    //...
}

struct MyTextField: View {
    @Binding var text: String //duplicated code (see MySecureTextField)
    let label: String //duplicated code (see MySecureTextField)

    var body: some View {
        TextFieldContainer(label: label) {
            TextField("", text: self.$text)
        }
    }
}

struct MySecureTextField: View {
    @Binding var text: String //duplicated code (see MyTextField)
    let label: String //duplicated code (see MyTextField)

    var body: some View {
        TextFieldContainer(label: label) {
            SecureField("", text: self.$text)
        }
    }
}

并以这种方式使用它们:

struct ContentView: View {
    @State private var text = ""
    @State private var text2 = ""

    var body: some View {
        VStack {
            MyTextField(text: $text, label: "Label")
            MySecureTextField(text: $text2, label: "Secure textfield")
        }
    }
}

我并不是真的不喜欢这种解决方案,但是在属性上有一些代码重复。如果有很多属性,则会有很多代码重复。另外,如果我改变了一些性能上TextFieldContainer,我应该改变。因此所有的意见,这可能是很多结构来改变的(MyTextFieldMySecureTextFieldMyEmailTextFieldMyBlaBlaTextField,等等)。

3-我的最后一次尝试使用与上述第二次尝试相同的方法,但是使用AnyView这种方式:

struct MySecureTextField: View {
    private let content: AnyView

    init(text: Binding, label: String) {
        cOntent= AnyView(TextFieldContainer(label: label) {
            SecureField("", text: text)
        })
    }

    var body: some View {
        content
    }
}

struct MyTextField: View {
    private let content: AnyView

    init(text: Binding, label: String) {
        cOntent= AnyView(TextFieldContainer(label: label) {
            TextField("", text: text)
        })
    }

    var body: some View {
        content
    }
}

与第二次尝试没有什么不同,我的直觉是我错过了执行此常见任务的正确方法(SwiftUI-y方法)。您能指出我正确的“设计模式”还是改善我描述的解决方案之一?对不起,很长的问题。



1> Quinn..:

您可以使用简单的if!

struct MyTextField: View {
    @Binding var text: String
    var label: String
    var secure: Bool = false

    var body: some View {
        VStack {
            HStack {
                Text(label)
                Spacer()
            }

            if secure {
                SecureField("", text: $text)
            } else {
                TextField("", text: $text)
            }

            Divider()
        }
        .padding()
    }
}

用法:

MyTextField(text: $text, label: "Label") // unsecure
MyTextField(text: $text, label: "Label", secure: true) // secure


推荐阅读
author-avatar
清醒还是迷惘_123
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有