อาร์เรย์รวมถึงมุมมองหลายประเภทใน Swift / SwiftUI

Aug 18 2020

ฉันต้องการสร้างมุมมองที่ผู้คนสามารถเลือกภาพพื้นหลังที่ต้องการได้ซึ่งรวมถึงรูปสี่เหลี่ยมผืนผ้าที่มีสีพื้นหน้าหรือรูปภาพ จนถึงตอนนี้ฉันสามารถใช้งานได้โดยการสร้างสิ่งนี้

โครงสร้าง:

struct BackgroundImage : Identifiable{
var background : AnyView
let id = UUID()
}

ฉันกำลังเพิ่มลงในอาร์เรย์เช่นนั้น

ดู

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"))))
    }

ซึ่งช่วยให้ฉันวนลูปผ่าน BackgroundImages แบบนั้นได้

ดู:

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))
        }
    }
}

อย่างไรก็ตามฉันไม่สามารถเพิ่มได้

 .resizable()
 .aspectRatio(contentMode: .fill)

สำหรับรูปภาพเนื่องจาก AnyView ไม่อนุญาตให้ทำเช่นนี้

มีวิธีที่ดีกว่าในการบรรลุสิ่งนี้หรือไม่? ฉันควรมีอาร์เรย์แยกกันสองอาร์เรย์สำหรับรูปร่าง / รูปภาพแทนหรือไม่? หรือมีโครงสร้างมุมมองอื่นที่จะเหมาะกว่านี้หรือไม่?

ขอบคุณ!

คำตอบ

1 vacawama Aug 18 2020 at 19:51

ดังที่ @ DávidPásztorกล่าวไว้ในความคิดเห็นการจัดเก็บ Views ใน ViewModel ของคุณเป็นการออกแบบที่ไม่ดี

จริงๆแล้วคุณต้องเก็บสีและชื่อภาพ ให้รหัสอาคารมุมมองสร้างมุมมองจริง

นี่คือการนำไปใช้งานที่เป็นไปได้

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)
                }
            }
        }
    }
}

หมายเหตุ:ฉันคิดว่าจะใช้enumเพื่อเก็บความแตกต่างระหว่าง imageName และสี แต่มันง่ายที่สุดที่จะใช้ตัวเลือกและจัดเก็บสิ่งที่ฉันต้องการ ด้วยอินเทอร์เฟซที่สัมผัสกับรหัสการสร้างมุมมองคุณสามารถเปลี่ยนการใช้งานได้อย่างง่ายดายตามที่คุณต้องการจัดเก็บข้อมูล