Swift / SwiftUI에서 여러보기 유형을 포함하는 배열

Aug 18 2020

사람들이 선호하는 배경 이미지를 선택할 수있는 뷰를 만들고 싶습니다. 여기에는 전경색이있는 직사각형이나 이미지가 포함됩니다. 지금까지 이것을 생성하여 작동하도록했습니다.

구조 :

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

이렇게 배열에 추가하고 있습니다.

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

이렇게하면 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에서 허용하지 않는 이미지의 경우.

이를 달성하는 더 좋은 방법이 있습니까? 대신 Shapes / Images에 대해 두 개의 별도 배열이 있어야합니까? 아니면 이것에 더 적합한 대체 View 구조체가 있습니까?

감사!

답변

1 vacawama Aug 18 2020 at 19:51

@ DávidPásztor가 주석에서 언급했듯이 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과 색상의 구분을 저장 하기 위해 를 사용하려고 생각 했지만 선택 사항을 사용하고 필요한 것을 저장하는 것이 가장 간단했습니다. 뷰 빌드 코드에 노출되는 인터페이스를 사용하면 정보를 저장하려는 방식으로 구현을 쉽게 변경할 수 있습니다.