Swift UI:グリッドビューで画像を呼び出す代わりにjsonファイルを作成するにはどうすればよいですか?

Nov 21 2020

私は壁紙アプリを作成しています。ビューの1つは、写真を追加するためのグリッドビューです。ここに表示されているのは、画像を含むグリッドビューです。

グリッド自体に画像を追加しましたが、スペースがあることに気付きました。グリッドビューに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ファイルの生データを構造体の配列にデコードしますImageSpecification。この構造体は、単一のアイテムがどのように見えるかを説明します。プロトコルに準拠させることで、Codableを使用できますJSONDecoder

画面上の更新はすべてメインスレッドで行う必要があります。そのため、新しいキューを使用して、メインスレッドのストレージに新しいアイテムをプッシュする必要があります。

DispatchQueue.main.async { }

ビュー内で、DataModel初期化時にデータをロードするクラスを使用できるようになりました。の内部ではLazyVGridForEachビューを使用してデータをループします。以来ForEachを期待ハッシュ可能IDのいずれかに準拠した完全な構造体作るHashable固有IDにプロトコル、又はポイント。IDは自動的に初期化されるため、jsonファイルにunqiueIDを指定する必要はありません。ただし、コンパイラの警告を防ぐために、コーディングキーを提供する必要があります(ここを参照)。