SwiftUI:通过单选在 iOS 13 上创建图像的 mx2 列网格列表
SwiftUI: Create a list of mx2 column grid of images on iOS 13 with single selection
我是 SwiftUI 的新手,我正在尝试将来自 API 的图像列表显示为 iOS 13 上的 mx2 网格。我能够创建网格并且还能够下载图像。现在我有 2 个问题,所有单元格都显示最后下载的图像,我需要找出一种方法来突出显示 selected 单元格的背景,它应该作为单个 selection,即.如果我 select 仅应 selected 的任何其他单元格,而其余单元格则变为 deselected。任何帮助表示赞赏。以下是我目前的代码。
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
}
那么对于选择部分,你可以新建一个变量
@State var selection = ""
并且在 onTapGesture
selection = "row=\(row), col=\(col)"
为了突出显示,您可以这样做:
.overlay(selection == "row=\(row), col=\(col)" ? Color.green.opacity(0.3): Color.white.opacity(0))
或者你可以使用背景或任何东西,只要它符合条件!
我能够使用这个库解决这个问题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
}
我是 SwiftUI 的新手,我正在尝试将来自 API 的图像列表显示为 iOS 13 上的 mx2 网格。我能够创建网格并且还能够下载图像。现在我有 2 个问题,所有单元格都显示最后下载的图像,我需要找出一种方法来突出显示 selected 单元格的背景,它应该作为单个 selection,即.如果我 select 仅应 selected 的任何其他单元格,而其余单元格则变为 deselected。任何帮助表示赞赏。以下是我目前的代码。
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
}
那么对于选择部分,你可以新建一个变量
@State var selection = ""
并且在 onTapGesture
selection = "row=\(row), col=\(col)"
为了突出显示,您可以这样做:
.overlay(selection == "row=\(row), col=\(col)" ? Color.green.opacity(0.3): Color.white.opacity(0))
或者你可以使用背景或任何东西,只要它符合条件!
我能够使用这个库解决这个问题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
}