在SwiftUI,一个List
会自动格式化这样传递给它的子视图,这样的东西:
List {
Text("A")
Text("B")
}
将导致在这两个文本的意见被正确放置,与他们等之间的分隔符...
另外,也可以混合静态和动态生成数据,如下所示:
List {
Text("A")
ForEach(foo) { fooElement in CustomView(fooElement) }
Text("B")
ForEach(bar) { barElement in CustomView(barElement) }
}
我的目标是写我自己的自定义类型,将允许这类使用其用户(即:一种观点认为,让用户提供使用新功能的建设者DSL,看法,并没有要求他们写自己的修饰符来把他们放在屏幕),但我不知道在所有要放什么东西在我的自定义视图的初始化器。
本机SwiftUI意见正在利用@ViewBuilder
和接收的通用型贴合,以View
,但他们能够提取元素(从,比方说,一个方式ForEach
视图)是神秘的,我敢肯定它甚至没有可能。
也许我错过了一些东西,所以我很好奇,想知道你对这个观点?
编辑:一个例子可能更清晰。 你们中许多人必须与设置在利用彼此的顶部卡在网上看到了很好的例子ZSack
,所以如果我想建立一个什么CardStack
类型,将允许我的用户这样写代码?
CardStack {
SomeView()
AnotherView()
ForEach(1...10) { i in
NumberView(i)
}
}
这将导致堆放在彼此的顶部12卡,请注意该类型不是同质的,我们使用ForEach
。
你的挑战的第一部分是搞清楚ViewBuilder。 至于数据从小孩到祖先的流程,请往下看:
通过使用偏好(检查我的文章https://swiftui-lab.com/communicating-with-the-view-tree-part-1/ ),你可以从儿童到祖先的信息流。
一旦你完全明白的喜好和让他们的工作,你可以尝试使执行更加干净透明,让你的筹码的最终用户甚至没有意识到他使用偏好。 要做到这一点,你可以使用一些视图扩展。 最终的代码可能是这个样子:
CardStack {
SomeView().card(title: "", border: .red)
AnotherView().card(title: "", border: .green)
ForEach(items) { item in
NumberView(item).card(item.name, border: .blue)
}
}
和你的.card()
实现可能是这样的:
extension View {
func card(title: String, border: Color) -> CardCustomizer<Self> {
return CardCustomizer(viewContent: self, title: title, border: border)
}
}
struct CardCustomizer<Content: View>: View {
public let viewContent: Content
public let title: String
public let border: Color
var body: some View {
viewContent.preference(MyCardPref.self, value: ...)
}
}
我认为这是最好的,如果你先试,以使其不查看扩展工作,所以你得到一个事情吧。 然后进行封装用的扩展偏好逻辑。 否则,有太多新的东西来处理。