I have Tuple with views of different types that are some View
, there can also be some Group that is also generic type. Now I consider how can I parse such structure to achieve array of views.
Here are initializer and debugger screenshot
public init<A: View, B: View>(@ViewBuilder content: () -> TupleView<(A, B)>) {
let views = content().value
self.childs = [AnyView(views.0), AnyView(views.1)]
}
UPDATE 1
I've tried to implement initializer which @ViewBuilder returns TupleView of two Groups, then I can enable different combinations of Groups in View builder by implementing all permutations of initializers.
public init<A: View, B: View>(@ViewBuilder content: () -> TupleView<(Group<A>, Group<B>)>) {
let groups = content().value
groups.0.content...
groups.1.content... // here content is internal
}
But here problem is that groups.0 which is first Group< TupleView < ... > doesn't provide public access to content property (it is marked internal ) So I cannot access content of this property. I have even tried Mirror(reflecting: groups.0) but it also doesn't help as I cannot cast its children values to appropriate TupleView as I doesn't know ? generics type.
UPDATE 2
So now the only workaround to enable addition of more then 10 views to my custom container and then layouting this views as I would is to implement my own custom Grouping view instead of Group!
struct Grouping: View {
let childs : [AnyView]
var body: some View {
EmptyView()
}
public init<A: View>(@ViewBuilder content: () -> A) {
// this init will be used for any non-supported number of TupleView
let view = content()
self.childs = [AnyView(view)]
}
// MARK: TupleView support
public init<A: View, B: View>(@ViewBuilder content: () -> TupleView<(A, B)>) {
let views = content().value
self.childs = [AnyView(views.0), AnyView(views.1)]
}
// ... other 10 init permutations returning TupleView of views
}
And in my custom container view then I can implement inits that take this Grouping TupleView.
public init(@ViewBuilder content: () -> TupleView<(Grouping, Grouping)>) {
let groups = content().value
self.childs = groups.0.childs + groups.1.childs
}
And it seams to do the job. I do not understand why Apple doesn't provide public access to Group content and its subviews. This way we have very limited way to make custom layouting components
You can try this:
func recursiveViewToViewList<V0: View>(viewGroup: V0) -> [AnyView] {
[AnyView(viewGroup)]
}
func recursiveViewToViewList<V0: View, V1: View>(viewGroup: TupleView<(V0,V1)>) -> [AnyView] {
[]
+ recursiveViewToViewList(viewGroup: viewGroup.value.0)
+ recursiveViewToViewList(viewGroup: viewGroup.value.1)
}
func recursiveViewToViewList<V0: View, V1: View, V2: View>(viewGroup: TupleView<(V0,V1,V2)>) -> [AnyView] {
[]
+ recursiveViewToViewList(viewGroup: viewGroup.value.0)
+ recursiveViewToViewList(viewGroup: viewGroup.value.1)
+ recursiveViewToViewList(viewGroup: viewGroup.value.2)
}
func recursiveViewToViewList<V0: View, V1: View, V2: View, V3: View>(viewGroup: TupleView<(V0,V1,V2,V3)>) -> [AnyView] {
[]
+ recursiveViewToViewList(viewGroup: viewGroup.value.0)
+ recursiveViewToViewList(viewGroup: viewGroup.value.1)
+ recursiveViewToViewList(viewGroup: viewGroup.value.2)
+ recursiveViewToViewList(viewGroup: viewGroup.value.3)
}
func recursiveViewToViewList<Data: Collection, ID: Hashable, Content: View>(viewGroup: ForEach<Data, ID, Content>) -> [AnyView] {
viewGroup.data.flatMap {
recursiveViewToViewList(viewGroup: viewGroup.content($0))
}
}
struct Grouping: View {
let childs: [AnyView]
public init<A: View>(@ViewBuilder content: () -> A) {
childs = recursiveViewToViewList(viewGroup: content())
}
}
EDIT: this doesn't work. Overload resolution is done before generic realization, so only the first function (the base case one) is resolved when you only have the : View
constraint on generic parameters. The best chance may be to do dynamic dispatch there (likely using reflection since you can't typecheck for a generic with open arguments), though I don't know whether it is possible, neither how to do it.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.