我基本上是在try 创建一些类似于内置buttonStyle
、labelStyle
等修饰符的东西.它们会影响所有嵌套的按钮/标签,无论它们嵌套得有多深.例如:
VStack {
VStack {
VStack {
Button("OK") {}
...
}
...
}
...
}
.buttonStyle(.bordered) // this changes the style of the button, even if it is deeply nested
我的目标是对我的自定义视图执行相同的操作.让我们称其为TwinTextsView
:
VStack {
VStack {
VStack {
TwinTexts(text1: "Foo", text2: "Bar")
...
}
...
}
...
}
.twinTextsStyle(CustomStyle()) // this changes the style of TwinTexts, even if it is deeply nested
其中CustomStyle
可以像ButtonStyle
一样实现,makeBody
方法接受具有两个视图的配置,表示文本
struct TwinTextsStyleConfiguration {
// not sure what types these should be. AnyView?
let text1: Text1
let text2: Text2
}
protocol TwinTextsStyle {
associatedtype Body: View
@ViewBuilder
func makeBody(configuration: TwinTextsStyleConfiguration) -> Body
}
struct CustomStyle: TwinTextsStyle {
func makeBody(configuration: TwinTextsStyleConfiguration) -> some View {
// let's suppose I want to put one text on top of the other.
VStack {
configuration.text1
configuration.text2
}
}
}
然后,TwinTexts
人将使用此样式,如下所示:
struct TwinTexts: View {
let text1: String
let text2: String
var body: some View {
// note that these are not of type "Text". I don't know what type they are as I will be adding view modifiers to them
// here I am using lineLimit as an example
let text1 = Text(text1).lineLimit(1)
let text2 = Text(text2).lineLimit(1)
// not sure how I would get the "style" here
style.makeBody(.init(text1: text1, text2: text2))
}
}
我想到的一个 idea 是使用定制的Environment
,因为.environment
适用于所有嵌套的视图.有两个问题:
-
style.makeBody
将返回any View
,它不能在body
中使用
struct TwinTextsStyleKey: EnvironmentKey {
static let defaultValue: any TwinTextsStyle = DefaultStyle()
}
extension EnvironmentValues {
var twinTextsStyle: any TwinTextsStyle {
get { self[TwinTextsStyleKey.self] }
set { self[TwinTextsStyleKey.self] = newValue }
}
}
extension View {
func twinTextsStyle(_ style: some TwinTextsStyle) -> some View {
self.environment(\.twinTextsStyle, style)
}
}
struct TwinTexts: View {
let text1: String
let text2: String
@Environment(\.twinTextsStyle) var style
var body: some View {
let text1 = Text(text1).lineLimit(1)
let text2 = Text(text2).lineLimit(1)
style.makeBody(.init(text1: text1, text2: text2)) // this returns "any View"
}
}
-
我不知道我应该为
TwinTextsStyleConfiguration
中的视图使用什么类型.我看了看
ButtonStyleConfiguration.Label
,根据文件,这是一个"类型擦除"的视图.这是AnyView
的实际用例吗?