ios 如何在可以生成视图但不是视图的结构体中使用@State和@Environment属性?

rvpgvaaj  于 2022-12-15  发布在  iOS
关注(0)|答案(1)|浏览(123)

我正在尝试创建一个视图样式,用于自定义我正在开发的SwiftUI视图。我用makeBody函数声明了一个协议,我将样式存储为@State属性,以便可以更新它,并且我从视图内部调用makeBody。该技术与what SwiftUI already does非常相似,但有一件事我无法理解。

问题

第一方视图样式有一个重要的行为是我无法复制的--那就是在自定义视图样式中使用@State@Environment或任何其他SwiftUI属性 Package 器。
例如,我可以实现下面的自定义ButtonStyle,它只将当前配色方案的值显示为按钮的内容。

struct MyButtonStyle: ButtonStyle {

    @Environment(\.colorScheme) var colorScheme

    func makeBody(configuration: Configuration) -> some View {
        Text(String(describing: colorScheme))
    }

}

struct MyView: View {

    var body: some View {
        Button("foo", action: {}).buttonStyle(MyButtonStyle())
    }

}

当我用.dark首选配色方案预览MyView时,MyButtonStylecolorScheme属性被更新,makeBody函数被再次调用,文本读作“dark”,这都是意料之中的。

现在,让我们看看我创建的自定义视图样式。

struct MyCustomStyle /* : CustomStyle */ {

    @Environment(\.colorScheme) var colorScheme

    @ViewBuilder func makeBody(configuration: CustomStyleConfiguration) -> some View {
        Text(String(describing: colorScheme))
    }

}

struct MyView: View {

    @State var style = MyCustomStyle()

    var body: some View {
        style.makeBody(configuration: .init())
    }

}

在上面的场景中,当我使用.dark首选配色方案预览MyView时,colorScheme属性没有更新,即使标签的前景色正确地选择了更改,文本也显示为“light”。

问题

如何使@State@Environment属性在自定义视图样式中工作,就像它们在ButtonStyle和视图中工作一样,而不向makeBody函数的实现引入任何样板文件?
我确信这是可能的,因为所有第一方视图样式都已经支持这一点,没有样式符合View,也没有实现私有_makeView API,该API手动向SwiftUI的图形添加依赖项(至少根据SwiftUI的模块接口)。

我尝试但没有成功

我试着在一个 Package 了MyView的视图的可计算body中初始化视图样式,但也不起作用。

struct ContentView: View {

    var body: some View {
        MyView(style: MyCustomStyle())
    }

}
不可接受的答案

将自定义makeBody函数的返回值 Package 在单独的视图中,并且colorScheme属性是该视图的一部分,这是一种已知的变通办法,可产生正确的行为。建议将此作为变通办法的答案将不被接受,因为此问题完全是关于 * 避免这种情况 *。
如果回答说不可能在符合View的类型之外使用@Environment@State,则将不予接受(因为这是可能的,请参见ButtonStyle),除非他们能够 * 证明 * 私有API是驱动这一点的原因。

yhuiod9q

yhuiod9q1#

我们无法访问与ColorScheme对应的EnvironmentKey,但是它的defaultValue必须是light,这就是为什么你可以在视图之外得到一个值。
您的类型实际上不会随EnvironmentValues一起提供,除非它是ViewViewModifierButtonStyle ......Apple实际上并没有提供被视为“视图层次结构的一部分”的协议的详尽列表。
您要做的是实现您自己的Style,但不幸的是,这目前是不可能的。

makeBody(configuration: Configuration)

例如,ButtonStyle文档告诉我们,
系统为视图层次结构中的每个Button示例调用此方法,其中此样式是当前按钮样式。
以下所有类型都符合相同的配置文件,您可以实现其中的一种样式,但不能创建符合某个父Style协议的类型。

如果你不遵守其中一个“视图层次结构”协议,那么依赖注入就不是依赖于环境而是依赖于环境。
x一个一个一个一个x一个一个二个x
你必须给予你真正想做的事情,除非你去苹果公司开发SwiftUI。但是,你应该评估一下你是否能摆脱一个有针对性的功能子集。
一个一个三个一个一个一个一个一个四个一个一个一个一个一个五个一个
你的问题也提到了State,但是你没有提供一个例子,你可能只需要在使用State时遵守DynamicProperty

相关问题