Swift UI:グリッドビューで画像を呼び出す代わりにjsonファイルを作成するにはどうすればよいですか?
私は壁紙アプリを作成しています。ビューの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)
}
}
回答
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
初期化時にデータをロードするクラスを使用できるようになりました。の内部ではLazyVGrid
、ForEach
ビューを使用してデータをループします。以来ForEach
を期待ハッシュ可能IDのいずれかに準拠した完全な構造体作るHashable
固有IDにプロトコル、又はポイント。IDは自動的に初期化されるため、jsonファイルにunqiueIDを指定する必要はありません。ただし、コンパイラの警告を防ぐために、コーディングキーを提供する必要があります(ここを参照)。