用于自定义视图的 SwiftUI ViewModifier
SwiftUI ViewModifier for custom View
有没有办法创建修改器来更新正在修改的视图中的 @State private var
?
我有一个自定义视图,returns 具有“动态”背景色的 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
}
}
}
到目前为止没有什么特别的。现在,我需要的是创建(也许)一个修饰符或类似的东西,以便在父视图中我可以将 @State private var color
的值从 .red
更改为其他颜色,如果我需要更多自定义的话子视图。我要实现的目标示例:
struct SomeOtherParentView: View {
var body: some View {
HStack(spacing: 20) {
ChildView()
ChildView(theText: "Hello world!")
.someModifierOrTheLike(color: Color.green) // <- what I think I need
}
}
}
我知道我可以从 var
中删除 private
关键字并将 color
作为构造函数中的参数传递(例如:ChildView(theText: "Hello World", color: .green)
),但是我不要认为这是解决这个问题的方法,因为如果我需要对子视图进行更多自定义,我最终会得到一个非常大的构造函数。
那么,关于如何实现我正在寻找的东西有什么想法吗?希望我解释了自己:)
谢谢!!!
使用自定义 ViewModifier 确实是一种帮助向用户公开更简单界面的方法,但是如何将自定义参数传递给视图(除了使用 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)
当然,如果您有多个自定义设置,或者如果这对用户来说太 low-level,您可以创建一个 ViewModifier 来公开其中的一个子集,或者创建一个封装样式的类型,例如SwiftUI 使用 .buttonStyle(_:)
这是您的视图,修饰符只是生成另一个经过修改的视图的函数,所以...这里有一些可能的简单方法来实现您想要的效果。
测试 Xcode 12 / iOS 14
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())
}
}
以下是根据 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())
}
}
有没有办法创建修改器来更新正在修改的视图中的 @State private var
?
我有一个自定义视图,returns 具有“动态”背景色的 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
}
}
}
到目前为止没有什么特别的。现在,我需要的是创建(也许)一个修饰符或类似的东西,以便在父视图中我可以将 @State private var color
的值从 .red
更改为其他颜色,如果我需要更多自定义的话子视图。我要实现的目标示例:
struct SomeOtherParentView: View {
var body: some View {
HStack(spacing: 20) {
ChildView()
ChildView(theText: "Hello world!")
.someModifierOrTheLike(color: Color.green) // <- what I think I need
}
}
}
我知道我可以从 var
中删除 private
关键字并将 color
作为构造函数中的参数传递(例如:ChildView(theText: "Hello World", color: .green)
),但是我不要认为这是解决这个问题的方法,因为如果我需要对子视图进行更多自定义,我最终会得到一个非常大的构造函数。
那么,关于如何实现我正在寻找的东西有什么想法吗?希望我解释了自己:) 谢谢!!!
使用自定义 ViewModifier 确实是一种帮助向用户公开更简单界面的方法,但是如何将自定义参数传递给视图(除了使用 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)
当然,如果您有多个自定义设置,或者如果这对用户来说太 low-level,您可以创建一个 ViewModifier 来公开其中的一个子集,或者创建一个封装样式的类型,例如SwiftUI 使用 .buttonStyle(_:)
这是您的视图,修饰符只是生成另一个经过修改的视图的函数,所以...这里有一些可能的简单方法来实现您想要的效果。
测试 Xcode 12 / iOS 14
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())
}
}
以下是根据 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())
}
}