微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

用于自定义视图的SwiftUI ViewModifier

如何解决用于自定义视图的SwiftUI ViewModifier

有没有一种方法可以创建修改器来更新正在修改的视图中的@State private var

我有一个自定义视图,该视图返回带有“动态”背景色的Text或带有带有“动态”前景色的Circle

struct ChildView: View {
    var theText = ""
    
    @State private var color = Color(.purple)
    
    var body: some View {
        HStack {
            if theText.isEmpty {          // If there's no theText,a Circle is created
                Circle()
                    .foregroundColor(color)
                    .frame(width: 100,height: 100)
            } else {                      // If theText is provided,a Text is created
                Text(theText)
                    .padding()
                    .background(RoundedRectangle(cornerRadius: 25.0)
                                    .foregroundColor(color))
                    .foregroundColor(.white)
            }
        }
    }
}

我在应用程序的不同部分重复使用此视图。如您所见,我需要指定的唯一参数是theText。因此,创建此ChildView的可能方法如下:

struct SomeParentView: View {
    var body: some View {
        vstack(spacing: 20) {
            ChildView()   // <- Will create a circle

            ChildView(theText: "Hello World!")   // <- Will create a text with background
        }
    }
}

enter image description here

到目前为止,还没有幻想。现在,我需要创建(也许是)修饰符等,以便在父视图中可以将@State private var color的值从.red更改为其他颜色,如果我需要对其进行更多自定义的话ChildView。我要实现的示例:

struct SomeOtherParentView: View {
    var body: some View {
        HStack(spacing: 20) {
            ChildView()

            ChildView(theText: "Hello World!")
                .someModifierOrTheLike(color: Color.green)   // <- what I think I need
        }
    }
}

我知道我可以从该private删除var关键字,并将color作为参数传递给构造函数(例如:ChildView(theText: "Hello World",color: .green)),但是我不知道认为这是解决此问题的方法,因为如果我需要在子视图上进行更多自定义,则最终会得到非常大的构造函数

那么,关于如何实现我所寻找的任何想法?希望我自己解释一下:) 谢谢!!!

解决方法

这是您的视图,修饰符只是生成另一个已修改视图的函数,所以...这是一些实现所需内容的简单方法。

通过Xcode 12 / iOS 14测试

demo

struct ChildView: View {
    var theText = ""
    
    @State private var color = Color(.purple)
    
    var body: some View {
        HStack {
            if theText.isEmpty {          // If there's no theText,a Circle is created
                Circle()
                    .foregroundColor(color)
                    .frame(width: 100,height: 100)
            } else {                      // If theText is provided,a Text is created
                Text(theText)
                    .padding()
                    .background(RoundedRectangle(cornerRadius: 25.0)
                                    .foregroundColor(color))
                    .foregroundColor(.white)
            }
        }
    }
    
    // simply modify self,as self is just a value
    public func someModifierOrTheLike(color: Color) -> some View {
        var view = self
        view._color = State(initialValue: color)
        return view.id(UUID())
    }
}
,

使用自定义ViewModifier确实是一种帮助向用户展示更简单的界面的方法,但是如何将自定义参数传递给View的一般思路(除了使用init之外)是通过环境变量.environment

struct MyColorKey: EnvironmentKey {
   static var defaultValue: Color = .black
}

extension EnvironmentValues {
   var myColor: Color {
      get { self[MyColorKey] }
      set { self[MyColorKey] = newValue }
   }
}

然后您可以在视图中依靠它:

struct ChildView: View {
   @Environment(\.myColor) var color: Color

   var body: some View {
      Circle()
         .foregroundColor(color)
         .frame(width: 100,height: 100)
   }
}

用法是:

ChildView()
   .environment(\.myColor,.blue)

您可以通过使用视图修饰符使它更好一些:

struct MyColorModifier: ViewModifier {
   var color: Color

   func body(content: Content) -> some View {
      content
         .environment(\.myColor,color)
   }
}

extension ChildView {
   func myColor(_ color: Color) { 
      self.modifier(MyColorModifier(color: color) 
   }
}

ChildView()
   .myColor(.blue)

当然,如果您有多个自定义设置,或者对于用户来说这太低级了,您可以创建一个ViewModifier来暴露其中的一个子集,或者创建一个封装样式的类型,就像SwiftUI对.buttonStyle(_:)

,

以下是根据 Asperi 的回答链接方法的方法:

struct ChildView: View {
    @State private var foregroundColor = Color.red
    @State private var backgroundColor = Color.blue

    var body: some View {
        Text("Hello World")
            .foregroundColor(foregroundColor)
            .background(backgroundColor)
    }

    func foreground(color: Color) -> ChildView {
        var view = self
        view._foregroundColor = State(initialValue: color)
        return view
    }

    func background(color: Color) -> ChildView {
        var view = self
        view._backgroundColor = State(initialValue: color)
        return view
    }
}

struct ParentView: View {
    var body: some View {
        ChildView()
            .foreground(color: .yellow)
            .background(color: .green)
            .id(UUID())
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?