I’m trying to make an array of Views so that, ideally, each element of the array can have a different composition of child View elements. I have tried to achieve this by creating an array of [some View]
. Apparently the compiler inspects the first element of the the array upon initializing the array and expects all elements have a similar composition of subviews. I’d appreciate any help to get around this problem or an alternative solution.
In the simplest form I have created an array of [some View]
with two VStack elements, yet each VStack contains two subviews, a Text and an Image with different layout order.
var myArray : [some View] = [
VStack{
Text("foo")
Image("foo_image")
},
VStack{
Image("bar_image")
Text("bar")
}
]
Apparently the compiler infers the type of array as () -> TuppleView<Text,Image>
by evaluating the first element and complains that the second element is of type () -> TuppleView<Image,Text>
can not be converted to the aforesaid type.
My question is that whether there is a way to hide the detail of the containing Views or wrap it in an opaque object so that I can create an array of Views with different elements and layout arrangements.
Here is a minimal reproducible example
struct WrapperView <Content : View> : View , Identifiable{
var id: String
let content : Content
var body: some View{
VStack{
Text("Some text")
content
}
}
init(id : String , @ViewBuilder content : ()-> Content){
self.id = id
self.content = content()
}
}
struct TheItemList {
static var theItems : [WrapperView< some View>] = [
WrapperView(id : "frist one" , content: {
HStack{
Text("foo")
Image(systemName: "heart")
}
}),
WrapperView(id : "second one" , content: {
HStack{
Image(systemName: "bolt")
Text("bar")
}
})
]
}
struct TestView : View {
var body: some View{
ScrollView{
ForEach(TheItemList.theItems , id: .id){item in
item
}
}
}
}
struct TestView_Previews: PreviewProvider {
static var previews: some View {
TestView()
}
}
Obviously everything is fine when the order of Text and Image elements in the second HStack matches the first one’s.
2
Answers
Problem Solved! Apparently wrapping the view items in AnyView can fix the problem, simple as that!
and this how it fixes the above mentioned example:
The way I would approach something like this…
You have an array of all sorts of different data. Swift doesn’t do heterogeneous arrays but we can get around this by creating an enum to hold the data…
Then in the view you give it an array of these and use that to create the views.
This will create all your different views based on the type of the enum and the contents held inside each case.