I'm new to SwiftUI and I'm trying to display a list of images from API as mx2 grids on iOS 13. I was able to create the grid and also able to download the images. Now I have 2 issues, all cells are showing the last downloaded image, and I need to figure out a way for highlighting the background of the selected cell which should work as a single selection, ie. if I select any other cell only that should be selected while the rest becomes deselected. Any help is appreciated. Below is my code so far.
struct MyListView: View {
@State var cardImage: Image = Image ("placeholder")
var myCard: [ImageDataModel] = []
let column = 2
var body: some View {
let itemsCount = myCard.count
let rowCount = itemsCount % 2 == 0 ? itemsCount/2 : itemsCount/2 1
ScrollView {
VStack(spacing: 20) {
ForEach(0..<rowCount, id: \.self) { row in
HStack(spacing: 20) {
ForEach(0..<column, id: \.self) { col in
if row == rowCount-1 && itemsCount%2 != 0 && col != 0 {
Rectangle()
.fill(Color.white)
.frame(width: UIScreen.main.bounds.width/2-20)
.aspectRatio(CGSize(width:148, height: 84), contentMode: .fit)
} else {
cardImage
.resizable()
.frame(width: UIScreen.main.bounds.width/2-20)
.cornerRadius(20)
.aspectRatio(CGSize(width:148, height: 84), contentMode: .fit)
.onTapGesture {
print("Tapped on image")
}
.onAppear {
getImage(cardModel: self.myCard[(row*2) col])
}
}
}
}
}
}
}
}
fileprivate func getImage(cardModel: ImageDataModel) {
let imageData = ImageData(withUrl: cardModel.imageUrl.medium,
completion: { (response) in
DispatchQueue.main.async {
switch response {
case .success(let downloadedImage, _):
//This image download works but fills all cell image with last downloaded data
cardImage = Image(uiImage: downloadedImage)
case .failure(let error):
print("Image Failure \(error)")
}
}
})
ImageDownloader.shared.downloadImage(withData: imageData)
}
}
struct ImageDataModel {
var imageId: Int
var imageUrl: String
}
CodePudding user response:
Well for the selection part, you can create a new variable
@State var selection = ""
and in the onTapGesture
selection = "row=\(row), col=\(col)"
for the highlight, you can do something like this:
.overlay(selection == "row=\(row), col=\(col)" ? Color.green.opacity(0.3): Color.white.opacity(0))
or you can use a background or anything as long as it uses the condition!
CodePudding user response:
I was able to solve this using this library WaterFallGrid
struct MyListView: View {
var myCard: [ImageDataModel] = []
var cardImage: Image = Image("placeholder")
@State var selection = ""
var body: some View {
ScrollView {
WaterfallGrid(myCard) { card in
CardImageView(myCard: card, cardImage: cardImage)
.border(selection == "\(card.id)" ? Color.blue : Color.white, width: 2.0)
.cornerRadius(5)
.onTapGesture {
print("Tapped on updated image = \(card.card)")
selection = "\(card.id)"
}
}
.gridStyle(
columns: 2
)
.padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10))
}
}
}
struct CardImageView: View {
@State var myCard: ImageDataModel
@State var cardImage: Image
var body: some View {
VStack {
cardImage
.resizable()
.frame(width: (UIScreen.main.bounds.width)/2.5)
.aspectRatio(5/3, contentMode: .fit)
.cornerRadius(5)
.onAppear {
getImage(cardModel: myCard)
}
}.padding(5)
}
struct ImageDataModel: Identifiable {
let id = UUID()
let imageUrl: String
}