I want to display a list of images. Each image have an associated text, and I want to display that text like a "popover" in style (but how it is achieved is not important - it doesn't have to be as a popover "call"), i.e. on top of the image but only as large as the text actually is, the image is supposed to be seen still in the background around the text.
I have the images in a HStack or VStack, depending on how the user holds the device and I have a button which I want to use to trigger showing the text. I have tried various ways of adding .popover modifier in various places without managing to show anything, including the Button. But I haven't gotten it to work in any way.
I'm fairly inexperienced, so the answer might be obvious!
The GrannyStreamDataItem data structure uses named images at the moment, but that will of course change later on.
How do I trigger and show the text when the user taps the i-button?
//Data structure
struct GrannyStreamDataItem: Identifiable {
var id = UUID()
var image: String
var comment: String = ""
var commentPosition: Alignment = .bottomLeading
}
let grannyStreamData: [GrannyStreamDataItem] = [
GrannyStreamDataItem(image: "Pisa1", comment: "Leaning tower of Pisa. Gosh, it is crowded!", commentPosition: .topLeading),
GrannyStreamDataItem(image: "Pisa2", comment: "This is what the tower looks like from the inside :-)", commentPosition: .topTrailing),
]
// View showing images
struct ContentView: View {
var body: some View {
GeometryReader { geometry in
if geometry.size.width > geometry.size.height {
ScrollView(.horizontal) {
VStack {
Spacer()
HStack {
ImageViews(dataItemArray: grannyStreamData)
}
Spacer()
}
}
} else {
ScrollView(.vertical) {
HStack {
Spacer()
VStack {
ImageViews(dataItemArray: grannyStreamData)
}
Spacer()
}
}
}
}
}
}
struct ImageViews: View {
let dataItemArray: [GrannyStreamDataItem]
var body: some View {
ForEach(dataItemArray) { dataItem in
ZStack(alignment:dataItem.commentPosition) {
Image(dataItem.image)
.resizable()
.aspectRatio(contentMode: .fit)
Button {
showTextImage(description: dataItem.comment)
} label: {
Image(systemName: "info.circle")
.padding(.all, 10)
.font(.largeTitle)
.foregroundColor(.black)
}
//.popover() here won't work... Why not?
}
}
}
func showTextImage(description: String) {
print("Image text: \(description)")
}
}
This is how I would do it:
I would favor a conditional view to a popover in this case. It has a more flexible appearance.
I renamed
ImageViewstoImageListto avoid any name confusion later on.I removed excessive
HStacks,VStacks andSpacers fromcontentView, they also are more trouble than use.I moved
ImageandTextto a new viewImageView. Like that, each of them can have its own@StatevariableshowComment. This variable can be toggled via anonTapGestureand the info image or the comment text will conditionally show. Note theif-condition needs to be enclosed by aGroupview to accept theonTapGesturemodifier. This Group is enclosed in aoverlaymodifier to stack over the image with the specified alignment.I also added an animation on the state change to make it a little smoother.