Array termasuk beberapa tipe tampilan di Swift / SwiftUI
Saya ingin membuat tampilan di mana orang dapat memilih gambar latar belakang yang mereka sukai, ini termasuk persegi panjang dengan warna latar depan atau gambar. Sejauh ini saya telah mengerjakan ini dengan membuat ini
Struktur:
struct BackgroundImage : Identifiable{
var background : AnyView
let id = UUID()
}
Saya menambahkannya ke array seperti itu
ViewModel:
class VM : ObservableObject{
@Published var imageViews : Array<BackgroundImage> = Array<BackgroundImage>()
init(){
imageViews.append(BackgroundImage(background: AnyView(Rectangle().foregroundColor(Color.green))))
imageViews.append(BackgroundImage(background: AnyView(Rectangle().foregroundColor(Color.yellow))))
imageViews.append(BackgroundImage(background: AnyView(Image("Testimage"))))
}
yang memungkinkan saya untuk mengulang melalui array BackgroundImages seperti itu
Melihat:
LazyVGrid(columns: [GridItem(.flexible()), GridItem(.flexible())]) {
ForEach(VM.imageViews, id: \.self.id) { view in
ZStack{
view.background
//.resizable()
//.aspectRatio(contentMode: .fill)
.frame(width: g.size.width/2.25, height: g.size.height/8)
.clipShape(RoundedRectangle(cornerRadius: 10, style: .continuous))
}
}
}
Namun saya tidak dapat menambahkan
.resizable()
.aspectRatio(contentMode: .fill)
untuk gambar karena AnyView tidak mengizinkan ini.
Adakah cara yang lebih baik untuk mencapai ini? Haruskah saya memiliki dua larik terpisah untuk Bentuk / Gambar saja? Atau apakah ada View struct alternatif yang lebih cocok untuk ini?
Terima kasih!
Jawaban
Seperti yang disebutkan @ DávidPásztor di komentar, adalah desain yang buruk untuk menyimpan Views di ViewModel Anda.
Sungguh Anda hanya perlu menyimpan warna dan nama gambar. Biarkan kode bangunan tampilan menyusun tampilan yang sebenarnya.
Berikut adalah implementasi yang mungkin.
struct BackgroundItem: Identifiable {
private let uicolor: UIColor?
private let imageName: String?
let id = UUID()
var isImage: Bool { imageName != nil }
var color: UIColor { uicolor ?? .white }
var name: String { imageName ?? "" }
init(name: String? = nil, color: UIColor? = nil) {
imageName = name
uicolor = color
}
}
class VM : ObservableObject{
@Published var imageItems: [BackgroundItem] = []
init() {
imageItems = [.init(color: .green),
.init(color: .blue),
.init(name: "TestImage")]
}
}
struct ContentView: View {
@ObservedObject var vm = VM()
var body: some View {
GeometryReader { g in
LazyVGrid(columns: [GridItem(.flexible()), GridItem(.flexible())]) {
ForEach(vm.imageItems) { item in
ZStack{
if item.isImage {
Image(item.name)
.resizable()
.aspectRatio(contentMode: .fill)
} else {
Color(item.color)
}
}
.frame(width: g.size.width/2.25, height: g.size.height/8)
.clipShape(RoundedRectangle(cornerRadius: 10, style: .continuous)
}
}
}
}
}
Catatan: Saya berpikir untuk menggunakan enum
untuk menyimpan perbedaan antara imageName dan warna, tetapi yang paling sederhana adalah menggunakan pilihan dan menyimpan yang saya butuhkan. Dengan antarmuka yang diekspos ke kode bangunan tampilan, Anda dapat dengan mudah mengubah penerapan ke cara yang Anda inginkan untuk menyimpan informasi.