Interface utilisateur Swift: comment créer un fichier JSON au lieu d'appeler l'image en mode grille?

Nov 21 2020

Je crée une application de fond d'écran et l'une des vues est une vue en grille pour ajouter des photos comme vous pouvez le voir ici: la vue en grille avec les images

J'ai ajouté des images à la grille elle-même, mais j'ai remarqué qu'elles avaient des espaces et je dois les regrouper pour pouvoir ajouter comme 50 images dans la vue de la grille, mais il m'est venu à l'esprit de créer un fichier JSON dans la vue de la grille et de le laisser lire il avec toutes les photos, mais je ne sais pas comment créer le JSON et le connecter à la vue en grille

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

Réponses

Nikolai Nov 21 2020 at 20:29

TL; DR

Ajoutez un nouveau fichier vide à votre projet et appelez-le ImageList.json. Collez les données suivantes dans le fichier 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
    }
]

Utilisez l'exemple de travail suivant ci-dessous:

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

Explication détaillée

Le fichier json créé fait partie de votre bundle. Pour accéder à ce fichier, vous pouvez créer une URL pointant vers lui avec:

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

Maintenant, créez une tâche qui s'exécute de manière asynchrone en arrière-plan avec

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

Dans cette tâche, décodez les données brutes du fichier json dans un tableau de la structure ImageSpecification. Cette structure décrit à quoi ressemble un élément unique. En le rendant conforme au protocole, Codablevous pouvez utiliser le JSONDecoder.

Toute mise à jour à l'écran doit être effectuée sur le fil principal. C'est pourquoi vous devez vous assurer de pousser les nouveaux éléments dans votre stockage sur le thread principal en utilisant une nouvelle file d'attente:

DispatchQueue.main.async { }

Dans votre vue, vous pouvez désormais utiliser votre DataModelclasse, qui charge les données lors de l'initialisation. À l'intérieur de LazyVGrid, une ForEachvue est utilisée pour parcourir les données. Puisque ForEachattend un identifiant hachable, rendez la structure complète conforme au Hashableprotocole ou pointez sur l'identifiant unique. Il n'est pas nécessaire de fournir un identifiant unqiue dans le fichier json, car l'identifiant est automatiquement initialisé. Vous devez cependant fournir les clés de codage pour éviter les avertissements du compilateur (voir ici ).