【问题标题】:Swift UI: how create json file instead of calling image in grid view?Swift UI:如何创建 json 文件而不是在网格视图中调用图像?
【发布时间】:2020-11-21 01:43:45
【问题描述】:

我正在创建一个壁纸应用程序,其中一个视图是用于添加图片的网格视图,您可以在此处看到:the grid view with the images

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

【问题讨论】:

    标签: arrays json swiftui


    【解决方案1】:

    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 文件的原始数据解码为结构 ImageSpecification 的数组。该结构描述了单个项目的外观。通过使其符合Codable 协议,您就可以使用JSONDecoder

    屏幕上的任何更新都必须在主线程上完成。这就是为什么您必须确保使用新队列将新项目推送到主线程的存储中:

    DispatchQueue.main.async { }
    

    在您的视图中,您现在可以使用 DataModel 类,它会在初始化时加载数据。在LazyVGrid 内部,ForEach 视图用于循环数据。由于ForEach 需要一个可散列的id,要么使完整的结构符合Hashable 协议,要么指向唯一的id。不需要在 json 文件中提供 unqiue id,因为 id 会自动初始化。但是,您必须提供编码密钥以防止编译器警告(请参阅here)。

    【讨论】:

    • 感谢您的帮助,我应用了您所说的内容,但视图始终未在画布中显示其崩溃并且不再显示任何内容,并且在调试中显示此错误 (020-11- 22 02:33:45.471645+0200 Joker[23636:1883592] . 模拟器用户要求新的图形质量:10) ...有什么想法吗?
    • 您是否尝试使用一个普通的新项目来测试它?您发布的消息似乎并不重要:stackoverflow.com/a/34265974/4354710您有最新的 macOS 和 XCode 版本吗?如果没有正确的错误消息,调试起来有点困难......
    • 是的,我确实有 Catalina macOS 和 Xcode 的最新版本。我有一个问题,我应该在预览中调用它吗? (((struct GridContentView_Previews: PreviewProvider { static var previews: some View { GridContentView() } } )))) 或者我应该在预览 idk 中调用解码器,我不明白有什么问题?
    • 我的建议是创建一个普通的新项目,并将ContentView.swift 的完整内容替换为上面的完整代码。记得将 json 文件添加到这个项目中。这对我来说很好。
    猜你喜欢
    • 2019-02-28
    • 1970-01-01
    • 2011-04-06
    • 1970-01-01
    • 2013-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多