Schnelle Benutzeroberfläche: Wie erstelle ich eine JSON-Datei, anstatt ein Bild in der Rasteransicht aufzurufen?

Nov 21 2020

Ich erstelle eine Hintergrund-App und eine der Ansichten ist eine Rasteransicht zum Hinzufügen von Bildern, wie Sie hier sehen können: die Rasteransicht mit den Bildern

Ich habe dem Raster selbst Bilder hinzugefügt, aber ich habe festgestellt, dass sie Leerzeichen enthalten, und ich muss sie gruppieren, damit ich der Rasteransicht etwa 50 Bilder hinzufügen kann. Es kam mir jedoch in den Sinn, der Rasteransicht eine JSON-Datei zu erstellen und sie lesen zu lassen Es enthält alle Bilder, aber ich weiß nicht, wie ich den JSON erstellen und mit der Rasteransicht verbinden soll

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

Antworten

Nikolai Nov 21 2020 at 20:29

TL; DR

Fügen Sie Ihrem Projekt eine neue leere Datei hinzu und rufen Sie sie auf ImageList.json. Fügen Sie die folgenden Daten in die JSON-Datei ein:

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

Verwenden Sie das folgende Arbeitsbeispiel:

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

Ausführliche Erklärung

Die erstellte JSON-Datei ist Teil Ihres Bundles. Um auf diese Datei zuzugreifen, können Sie eine URL erstellen, die darauf verweist:

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

Erstellen Sie nun eine Aufgabe, die im Hintergrund asynchron ausgeführt wird

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

Dekodieren Sie innerhalb dieser Task die Rohdaten der JSON-Datei in ein Array der Struktur ImageSpecification. Diese Struktur beschreibt, wie ein einzelnes Element aussieht. Indem Sie es an das Protokoll anpassen, Codablekönnen Sie das verwenden JSONDecoder.

Jede Aktualisierung auf dem Bildschirm muss im Hauptthread erfolgen. Aus diesem Grund müssen Sie sicherstellen, dass neue Elemente mithilfe einer neuen Warteschlange in Ihren Speicher im Hauptthread verschoben werden:

DispatchQueue.main.async { }

In Ihrer Ansicht können Sie jetzt Ihre DataModelKlasse verwenden, die die Daten bei der Initialisierung lädt. Innerhalb von LazyVGridwird eine ForEachAnsicht verwendet, um die Daten zu durchlaufen. Da ForEacheine Hash-ID erwartet wird, muss entweder die vollständige Struktur dem HashableProtokoll entsprechen oder auf die eindeutige ID verweisen. Es ist nicht erforderlich, eine eindeutige ID in der JSON-Datei anzugeben, da die ID automatisch initialisiert wird. Sie müssen jedoch die Codierungsschlüssel angeben, um Compiler-Warnungen zu vermeiden (siehe hier ).