我\xe2\x80\x99m 尝试创建一个视图样式来自定义我\xe2\x80\x99m 开发的自定义SwiftUI 视图。我声明了一个带有makeBody函数的协议,I\xe2\x80\x99m 将样式存储为@State属性以便可以更新,并且 I\xe2\x80\x99mmakeBody从视图内部调用。这项技术与 SwiftUI 已经做的非常相似,但是有一件事情我无法弄清楚。
\xe2\x80\x99s 第一方视图样式具有的一个重要行为,我可以\xe2\x80\x99t 使用@State、@Environment或任何其他 SwiftUI 属性包装器复制 \xe2\x80\x94 that\xe2\x80\x99s在自定义视图样式内。
例如,我可以实现以下自定义ButtonStyle,仅将当前配色方案的值显示为按钮\xe2\x80\x99s 内容。
struct MyButtonStyle: ButtonStyle {\n\n @Environment(\\.colorScheme) var colorScheme\n\n func makeBody(configuration: Configuration) -> some View {\n Text(String(describing: colorScheme))\n }\n\n}\n\nstruct MyView: View {\n\n var body: some View {\n Button("foo", action: {}).buttonStyle(MyButtonStyle())\n }\n\n}\nRun Code Online (Sandbox Code Playgroud)\n当我MyView使用.dark首选配色方案进行预览时, 的colorScheme属性MyButtonStyle被更新,makeBody 函数被再次调用,并且文本显示为 \xe2\x80\x9cdark\xe2\x80\x9d。这都是预料之中的。

现在,让\xe2\x80\x99s 看看我创建的自定义视图样式。
\nstruct MyCustomStyle /* : CustomStyle */ {\n\n @Environment(\\.colorScheme) var colorScheme\n\n @ViewBuilder func makeBody(configuration: CustomStyleConfiguration) -> some View {\n Text(String(describing: colorScheme))\n }\n\n}\n\nstruct MyView: View {\n\n @State var style = MyCustomStyle()\n\n var body: some View {\n style.makeBody(configuration: .init())\n }\n\n}\nRun Code Online (Sandbox Code Playgroud)\n在上述场景中,当我MyView使用.dark首选配色方案进行预览时,该colorScheme属性不会更新,并且文本显示为 \xe2\x80\x9clight\xe2\x80\x9d,即使标签的前景色已正确拾取改变。

如何使@State和@Environment属性在自定义视图样式中工作,就像它们在ButtonStyle视图中工作一样,而不在makeBody函数的实现中引入任何样板文件?
我确信这是可能的,因为所有第一方视图样式都已经支持这一点,没有符合 的样式View,并且没有它们实现_makeView手动将依赖项添加到 SwiftUI 图形的私有 API(至少根据)的模块接口SwiftUI。
body我尝试在包装的视图的可计算内部初始化视图样式MyView。这也行不通。
struct ContentView: View {\n\n var body: some View {\n MyView(style: MyCustomStyle())\n }\n\n}\nRun Code Online (Sandbox Code Playgroud)\n将自定义函数的返回值包装makeBody在单独的视图中,并将colorScheme属性作为该视图的一部分,是一种已知的解决方法,可以产生正确的行为。建议将此作为解决方法的答案将不会被接受,因为这个问题完全是为了避免这种情况。
回答说不可能使用@Environment或@State超出符合的类型View将不会被接受(因为这是可能的,请参阅参考资料ButtonStyle),除非他们可以证明私有 API 是驱动此问题的原因。
小智 2
我们无权访问与EnvironmentKey对应的任何 is ColorScheme,但它defaultValue必须是light。这就是为什么你可以在视图之外获得值。
你的类型实际上不会被提供,EnvironmentValues除非它是 a 、View、ViewModifier、ButtonStyle\xe2\x80\xa6Apple 实际上并没有提供被视为“视图层次结构的一部分”的协议的详尽列表。
您正在尝试做的事情(不幸的是目前不可能)是实现您自己的Style. 没有所有内置函数都Style使用的协议,需要实现
makeBody(configuration: Configuration)\nRun Code Online (Sandbox Code Playgroud)\n例如,ButtonStyle文档告诉我们,
\n\n系统为视图层次结构中的每个 Button 实例调用此方法,其中此样式是当前按钮样式。
\n
以下所有内容均符合相同的配置文件。您可以实现其中一种样式,但无法创建符合某些父Style协议的类型。
如果您不符合“视图层次结构”协议之一,则不需要依赖环境,而是需要依赖项注入。例如
\nstruct MyCustomStyle {\n init(environment: EnvironmentValues) {\n colorScheme = environment.colorScheme\n }\n\n private let colorScheme: ColorScheme\n\n @ViewBuilder func makeBody() -> some View {\n Text(String(describing: colorScheme))\n }\n}\nRun Code Online (Sandbox Code Playgroud)\nstruct ContentView: View {\n @Environment(\\.self) private var environment\n\n var style: MyCustomStyle { .init(environment: environment) }\n\n var body: some View {\n style.makeBody()\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n除非你去 Apple 从事 SwiftUI 工作,否则你必须放弃你真正想做的事情。但是,您应该评估是否可以摆脱目标功能子集。例如
\nstruct MyCustomStyle: ViewModifier {\n struct CustomStyleConfiguration { }\n\n @Environment(\\.colorScheme) var colorScheme\n\n init(configuration: CustomStyleConfiguration = .init()) {\n self.configuration = configuration\n }\n\n func body(content: Content) -> some View {\n Text(String(describing: colorScheme))\n }\n\n private let configuration: CustomStyleConfiguration\n}\nRun Code Online (Sandbox Code Playgroud)\nstruct MyView: View {\n var body: some View {\n EmptyView()\n }\n}\n\nextension MyView {\n func style(_ style: MyCustomStyle = .init()) -> some View {\n modifier(style)\n }\n}\nRun Code Online (Sandbox Code Playgroud)\nMyView().style()\nRun Code Online (Sandbox Code Playgroud)\n您的问题还提到了State,但您没有提供示例。您可能只需要遵守DynamicProperty您正在做的任何事情State。
| 归档时间: |
|
| 查看次数: |
899 次 |
| 最近记录: |