I've been playing with this MirrorView to display SwiftUI Hierarchy in a Tree. It's works pretty great until a custom View is introduced. Then the body type of the View is not shown, only its name.
struct ContentView: View {
var body: some View {
VStack {
Text("Lorem Ipsum")
CustomView()
}
.mirror()
}
}
struct CustomView: View {
var body: some View {
HStack {
Text("Hello")
Text("Word")
}
}
}
The problem is that the Mirror for ContentView is VStack<TupleView<(Text, CustomView)>>.
I was actually able to solve the problem by propagating the CustomView.Body type through PreferenceKey and replace the occurrence of ContentView by CustomView<HStack<TupleView<(Text, Text)>>>.
The downside of this approach is that I have to manually propagate the body type for every custom view.
struct CustomView: View {
var body: some View {
HStack {
Text("Hello")
Text("Word")
}
.propagateBodyType(self)
}
}
I wonder if there is a way to go from VStack<TupleView<(Text, CustomView)>> to VStack<TupleView<(Text, CustomView<HStack<TupleView<(Text, Text)>>>)>> just using reflection. Does anyone have any ideas?
xAlien95
(Stefano De Carolis)
2
SwiftUI's ViewBuilder doesn't provide a buildExpression static method, so one option could be to "inject" one yourself:
var customViews: [String: String] = [:]
extension ViewBuilder {
static func buildExpression<T: View>(_ expression: T) -> T {
if !(T.Body.self is Never.Type) {
customViews["\(T.self)"] = "\(T.Body.self)"
}
return expression
}
}
With your code sample, customViews will contain the following:
[
"CustomView": "HStack<TupleView<(Text, Text)>>",
"ContentView": "VStack<TupleView<(Text, CustomView)>>"
]
You can then manually (and recursively) find and replace all the occurrences of those view names. It looks like Chris Eidhof's implementation is string-based, so it should suffice.
2 Likes
That’s simple and clever! Thank you! 