首页 > 解决方案 > Swift UI:如何创建 json 文件而不是在网格视图中调用图像?

问题描述

我正在创建一个壁纸应用程序,其中一个视图是用于添加图片的网格视图,如您在此处看到的:带有图像的网格视图

我将图像添加到网格本身,但我注意到它们有空格,我必须对它们进行分组,这样我才能在网格视图中添加 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)
        }
                }
        

标签: arraysjsonswiftui

解决方案


TL; 博士

将一个新的空文件添加到您的项目并调用它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类,该类在初始化时加载数据。在内部LazyVGridForEach视图用于循环数据。由于ForEach需要一个可散列的 id,要么使完整的结构符合Hashable协议,要么指向唯一的 id。不需要在 json 文件中提供 unqiue id,因为 id 会自动初始化。但是,您必须提供编码密钥以防止编译器警告(请参阅此处)。


推荐阅读