【问题标题】:Difference between creating ViewModifier and View extension in SwiftUI在 SwiftUI 中创建 ViewModifier 和 View 扩展的区别
【发布时间】:2019-12-16 02:37:33
【问题描述】:

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

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()
)

【问题讨论】:

    标签: ios swift swiftui


    【解决方案1】:

    您提到的所有方法都是正确的。不同之处在于您如何使用它以及在何处访问它。 哪个更好?是一个基于意见的问题,您应该查看干净的代码策略和 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")
                }
            }
        }
    }
    

    我们应该拭目以待,看看像这样的新技术中有哪些最佳做法。我们现在发现的任何东西都只是一种GOOD做法。

    【讨论】:

    • 对我来说,extension 看起来几乎适用于我可以成像的所有情况。这就是我认为 ViewModifier+ModifiedContent 是多余的原因。我们可以通过扩展和视图结构来实现这两个东西。 :)
    • 如你所说,几乎
    • ViewModifier 让您拥有@State 变量,但视图扩展没有。
    • 扩展永远不能存储变量。 @States 属于视图,而不是修饰符。
    • @MojtabaHosseini 我知道扩展永远不能有存储变量。那是我的观点!但是 ViewModifier 可以有,我贴了一个例子。
    【解决方案2】:

    我通常更喜欢扩展,因为它们可以为您提供更易读的代码并且它们通常更短。 事实上,我目前正在撰写一篇包含一些技巧的文章。 我完成了一篇关于 View 扩展的文章,可在 here 获取。

    但是,还是有区别的。最后一个。使用 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()
            }
        }
    }
    

    【讨论】:

    • 为什么要创建一个视图然后struct ColorChangeView: View
    • 这只是一个例子。当然这种情况不需要它。它的唯一目的是向您展示@State 变量在ViewModifier 中是允许的。最初的问题不是 View extensions 和 ViewModifier 有什么区别吗?你有一个;-)
    • 好点。但我只是想找出为什么苹果开发者创造了这样一个结构,如果它没有提供任何不透明的优势。 :)
    • 好吧,考虑一下我发布的示例。您将如何以可以应用于不同视图的方式编写该逻辑(无需为每个视图重写相同的代码)?您不能使用 View 扩展,因为您无法跟踪内部状态。您不能使用自定义视图,因为您不能重用逻辑将其应用于其他视图。您只能使用 ViewModifier。 (续)
    • View扩展的目的是什么?可能有两个原因: 1. 视图扩展不是 SwiftUI 特有的。任何结构的扩展都是语言的一部分。那么如何防止人们使用它们呢? 2.,视图扩展看起来比修饰符好得多。因此,如果可以选择,我会进行扩展;-) 顺便说一句,您发布的问题很好!
    【解决方案3】:

    我认为最好的方法是结合 ViewModifiers 和 View 扩展。这将允许在 ViewModifier 中组合 @State 并方便 View 扩展。

    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 {
            ModifiedContent(content: self, modifier: PrimaryLabel())
        }
    }
    

    用法

    Text(tech.title)
        .makePrimaryLabel()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-03-09
      • 1970-01-01
      • 2012-08-11
      • 2011-03-30
      • 2022-08-11
      • 2014-09-10
      • 2010-11-17
      • 1970-01-01
      相关资源
      最近更新 更多