Swift UI : 그리드보기에서 이미지를 호출하는 대신 json 파일을 만드는 방법은 무엇입니까?

Nov 21 2020

나는 벽지 앱을 만들고 있으며보기 중 하나는 여기에서 볼 수 있듯이 사진을 추가하기위한 격자보기입니다. 이미지가있는 격자보기

그리드 자체에 이미지를 추가했지만 공백이 있음을 발견했으며 그리드 뷰에 50 개의 이미지를 추가 할 수 있도록 그룹화해야하지만 그리드 뷰에 JSON 파일을 만들고 읽을 수 있도록하는 것이 마음에 들었습니다. 그것에 모든 사진이 있지만 JSON을 만들고 그리드 뷰에 연결하는 방법을 모르겠습니다.

struct GridContentView: View {


var items = Item.stubs
let data = (1...1000).map { "Item \($0)" }


let columns = [
    GridItem(.adaptive(minimum: 80)),
    GridItem(.adaptive(minimum: 80)),
    GridItem(.adaptive(minimum: 80))
    
]
let rows = [
    GridItem(.adaptive(minimum: 80)),
    GridItem(.adaptive(minimum: 80)),
    GridItem(.adaptive(minimum: 80))
    
]
var body: some View {
    ScrollView {
                Section{
        LazyVGrid(columns: columns, spacing: 30) {
                // adding images
            
                Image("joker1")
                    .resizable()
                    .frame(width: 100, height: 200)
                    Image("joker2")
                .resizable()
                .frame(width: 100, height: 200)
                 Image("joker3")
                     .resizable()
                     .frame(width: 100, height: 200)
                     Image("joker4")
                 .resizable()
                 .frame(width: 100, height: 200)
                 Image("joker5")
                     .resizable()
                     .frame(width: 100, height: 200)
                     Image("joker6")
                 .resizable()
                 .frame(width: 100, height: 200)
                 Image("joker7")
                     .resizable()
                     .frame(width: 100, height: 200)
                     Image("joker8")
                 .resizable()
                 .frame(width: 100, height: 200)
                 Image("joker9")
                     .resizable()
                     .frame(width: 100, height: 200)
                     Image("joker10")
                 .resizable()
                 .frame(width: 100, height: 200)
        }
                }
        

답변

Nikolai Nov 21 2020 at 20:29

TL; DR

새 빈 파일을 프로젝트에 추가하고 이름을 ImageList.json. 다음 데이터를 json 파일에 붙여 넣습니다.

[
    {
        "name": "image1",
        "width": 100.0,
        "height": 200.0
    },
    {
        "name": "image2",
        "width": 100.0,
        "height": 200.0
    },
    {
        "name": "image3",
        "width": 100.0,
        "height": 200.0
    }
]

아래 작업 예제를 사용하십시오.

import SwiftUI

struct ImageSpecification: Codable {
    let id = UUID()
    let name: String
    let width: CGFloat
    let height: CGFloat
    
    private enum CodingKeys: CodingKey {
        case name
        case width
        case height
    }
}

class DataModel: ObservableObject {
    @Published var images: [ImageSpecification] = []
    
    init() {
        DispatchQueue.global(qos: .background).async {
            if let jsonURL = Bundle.main.url(forResource: "ImageList", withExtension: "json") {
                let jsonData = try! Data(contentsOf: jsonURL)

                let jsonDecoder = JSONDecoder()
                let objects = try! jsonDecoder.decode([ImageSpecification].self, from: jsonData)

                DispatchQueue.main.async {
                    self.images.append(contentsOf: objects)
                }
            }
        }
    }
}

struct ContentView: View {
    @StateObject var model = DataModel()
    
    let columns = [
        GridItem(.adaptive(minimum: 80)),
        GridItem(.adaptive(minimum: 80)),
        GridItem(.adaptive(minimum: 80))
    ]
    
    var body: some View {
        ScrollView {
            LazyVGrid(columns: columns, spacing: 30) {
                ForEach(self.model.images, id:\.self.id) { item in
                    Image(item.name)
                        .resizable()
                        .frame(width: item.width, height: item.height)
                }
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

상해

생성 된 json 파일은 번들의 일부입니다. 이 파일에 액세스하려면 다음을 사용하여 파일을 가리키는 URL을 만들 수 있습니다.

Bundle.main.url(forResource: "ImageList", withExtension: "json")

이제 백그라운드에서 비동기로 실행되는 작업을 만듭니다.

DispatchQueue.global(qos: .background).async { }

이 작업 내에서 json 파일의 원시 데이터를 struct 배열로 디코딩합니다 ImageSpecification. 이 구조체는 단일 항목이 어떻게 보이는지 설명합니다. 프로토콜 Codable을 준수하도록함으로써 JSONDecoder.

화면의 모든 업데이트는 메인 스레드에서 수행되어야합니다. 그렇기 때문에 새 대기열을 사용하여 새 항목을 기본 스레드의 저장소로 푸시해야합니다.

DispatchQueue.main.async { }

이제 뷰 내 DataModel에서 초기화시 데이터를로드하는 클래스를 사용할 수 있습니다 . 내측 LazyVGrid하는 ForEach뷰는 데이터를 통해 루프에 사용된다. ForEach해시 가능한 ID를 예상 하므로 Hashable프로토콜을 준수하는 완전한 구조체를 만들 거나 고유 ID를 가리 킵니다. ID가 자동으로 초기화되기 때문에 json 파일에 unqiue ID를 제공 할 필요가 없습니다. 그러나 컴파일러 경고를 방지하려면 코딩 키를 제공해야합니다 ( 여기 참조 ).