如何在SwiftUI中循环viewbuilder内容子视图
因此,我尝试创建一个视图,它接受viewBuilder内容,在内容的视图上循环,并在每个视图和其他视图之间添加分隔符如何在SwiftUI中循环viewbuilder内容子视图,swiftui,custom-view,viewbuilder,Swiftui,Custom View,Viewbuilder,因此,我尝试创建一个视图,它接受viewBuilder内容,在内容的视图上循环,并在每个视图和其他视图之间添加分隔符 struct BoxWithDividerView<Content: View>: View { let content: () -> Content init(@ViewBuilder content: @escaping () -> Content) { self.content = content }
struct BoxWithDividerView<Content: View>: View {
let content: () -> Content
init(@ViewBuilder content: @escaping () -> Content) {
self.content = content
}
var body: some View {
VStack(alignment: .center, spacing: 0) {
// here
}
.background(Color.black)
.cornerRadius(14)
}
}
如何做到这一点?所以我最终做了这个
@_functionBuilder
struct UIViewFunctionBuilder {
static func buildBlock<V: View>(_ view: V) -> some View {
return view
}
static func buildBlock<A: View, B: View>(
_ viewA: A,
_ viewB: B
) -> some View {
return TupleView((viewA, Divider(), viewB))
}
}
@\u functionBuilder
结构UIViewFunctionBuilder{
静态func构建块(view:V)->一些视图{
返回视图
}
静态func构建块(
_A:A,
_视图B:B
)->一些观点{
返回TupleView((viewA,Divider(),viewB))
}
}
然后我像这样使用我的函数生成器
struct BoxWithDividerView<Content: View>: View {
let content: () -> Content
init(@UIViewFunctionBuilder content: @escaping () -> Content) {
self.content = content
}
var body: some View {
VStack(spacing: 0.0) {
content()
}
.background(Color(UIColor.AdUp.carbonGrey))
.cornerRadius(14)
}
}
struct-BoxWithDividerView:View{
让内容:()->内容
init(@UIViewFunctionBuilder内容:@escaping()->content){
self.content=内容
}
var body:一些观点{
VStack(间距:0.0){
内容()
}
.背景(颜色(UIColor.AdUp.carbonGrey))
.转弯半径(14)
}
}
但问题是,这只适用于最多2个表达式视图。我将发布一个单独的问题,关于如何将数组传递给它,我刚刚回答了另一个类似的问题。链接答案将对此进行任何改进,因此请首先检查 然而,这里的答案是相同的
TupleView
扩展名,但不同的视图代码
用法:
struct ContentView: View {
var body: some View {
BoxWithDividerView {
Text("Something 1")
Text("Something 2")
Text("Something 3")
Image(systemName: "circle") // Different view types work!
}
}
}
您的带有分隔视图的框
:
struct BoxWithDividerView: View {
let content: [AnyView]
init<Views>(@ViewBuilder content: @escaping () -> TupleView<Views>) {
self.content = content().getViews
}
var body: some View {
VStack(alignment: .center, spacing: 0) {
ForEach(content.indices) { index in
if index != 0 {
Divider()
}
content[index]
}
}
// .background(Color.black)
.cornerRadius(14)
}
}
结果:
我敢肯定,使用
ViewBuilder
无法做到这一点-它只提供一个由基础视图组合而成的单一视图。如果要保持相同的DSL语法,需要实现自己的@\u functionBuilder
,类似于ViewBuilder
,您知道如何实现吗?我正在尝试使用@u functionBuilder:@u functionBuilder struct UIViewFunctionBuilder{static func buildBlock(u-views:[V])->一些视图{return ForEach(views){View in View Divider()}}},但是V应该符合可识别性。有些视图是在线的。我没有亲自做过,所以我帮不了你。如果您有一个关于实现@\u functionBuilder
的更具体的问题,您可以问另一个问题,我正试图完成完全相同的任务。你有没有提出过一个更健壮的解决方案,可以处理任意数量的视图?@ab1470没有:(如果有需要,请告诉我)do@ab1470请参见下文。@Eddy也会打电话给你:)
struct BoxWithDividerView: View {
let content: [AnyView]
init<Views>(@ViewBuilder content: @escaping () -> TupleView<Views>) {
self.content = content().getViews
}
var body: some View {
VStack(alignment: .center, spacing: 0) {
ForEach(content.indices) { index in
if index != 0 {
Divider()
}
content[index]
}
}
// .background(Color.black)
.cornerRadius(14)
}
}
extension TupleView {
var getViews: [AnyView] {
makeArray(from: value)
}
private struct GenericView {
let body: Any
var anyView: AnyView? {
AnyView(_fromValue: body)
}
}
private func makeArray<Tuple>(from tuple: Tuple) -> [AnyView] {
func convert(child: Mirror.Child) -> AnyView? {
withUnsafeBytes(of: child.value) { ptr -> AnyView? in
let binded = ptr.bindMemory(to: GenericView.self)
return binded.first?.anyView
}
}
let tupleMirror = Mirror(reflecting: tuple)
return tupleMirror.children.compactMap(convert)
}
}