在SwiftUI中创建ViewModifier和View扩展之间的区别

时间:2019-08-08 11:36:15

标签: ios swift swiftui

我正在尝试找出这两种方法之间的实际区别。例如:

struct PrimaryLabel: ViewModifier {
    func body(content: Content) -> some View {
        content
            .padding()
            .background(Color.black)
            .foregroundColor(Color.white)
            .font(.largeTitle)
            .cornerRadius(10)
    }
}

extension View {
    func makePrimaryLabel() -> some View {
        self
            .padding()
            .background(Color.black)
            .foregroundColor(Color.white)
            .font(.largeTitle)
            .cornerRadius(10)
    }
}

然后我们可以通过以下方式使用所有这些对象:

Text(tech.title)
    .modifier(PrimaryLabel())
Text(tech.title)
    .makePrimaryLabel()
ModifiedContent(
    content: Text(tech.title),
    modifier: PrimaryLabel()
)

2 个答案:

答案 0 :(得分:4)

您提到的所有方法都是正确的。区别在于您如何使用它以及在何处访问它。 哪个更好?是一个基于意见的问题,您应该查看简洁的代码策略和SOLID原则等,以找到每种情况的最佳实践。

由于SwiftUI是非常修饰符链的基础,因此第二个选项最接近原始修饰符。您也可以接受诸如原始文件这样的参数:

extension Text {
    enum Kind {
        case primary
        case secondary
    }

    func style(_ kind: Kind) -> some View {

        switch kind {
        case .primary:
            return self
                .padding()
                .background(Color.black)
                .foregroundColor(Color.white)
                .font(.largeTitle)
                .cornerRadius(10)

        case .secondary:
            return self
                .padding()
                .background(Color.blue)
                .foregroundColor(Color.red)
                .font(.largeTitle)
                .cornerRadius(20)
        }
    }
}

struct ContentView: View {
    @State var kind = Text.Kind.primary

    var body: some View {
        VStack {
        Text("Primary")
            .style(kind)
            Button(action: {
                self.kind = .secondary
            }) {
                Text("Change me to secondary")
            }
        }
    }
}

我们应该拭目以待,看看像这样的新技术中的最佳实践是什么。我们现在发现的一切只是一种良好的做法。

答案 1 :(得分:4)

我通常更喜欢扩展,因为它们使您的代码更具可读性,并且编写起来通常更短。 事实上,我目前正在撰写具有一些技巧的文章。我写了一篇有关here提供的有关View扩展的文章。

但是,有区别。最后一个。使用ViewModifier,您可以使用@State变量,但不能使用View扩展名。这是一个示例:

struct ContentView: View {
    var body: some View {
        VStack {
            Text("Hello, how are you?").modifier(ColorChangeOnTap())
        }
    }
}

struct ColorChangeOnTap: ViewModifier {
    @State private var tapped: Bool = false

    func body(content: Content) -> some View {
        return content.foregroundColor(tapped ? .red : .blue).onTapGesture {
            self.tapped.toggle()
        }
    }
}