Swift UI: jak utworzyć plik json zamiast wywoływać obraz w widoku siatki?
Tworzę aplikację do tapet, a jeden z widoków to widok siatki do dodawania zdjęć, jak widać tutaj: widok siatki z obrazami
Dodałem obrazy do samej siatki, ale zauważyłem, że mają spacje i muszę je pogrupować, więc mogę dodać około 50 obrazów w widoku siatki, ale przyszło mi do głowy, aby utworzyć plik JSON w widoku siatki i pozwolić mu czytać zawiera wszystkie zdjęcia, ale nie wiem, jak utworzyć JSON i podłączyć go do widoku siatki
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)
}
}
Odpowiedzi
TL; DR
Dodaj nowy pusty plik do swojego projektu i nadaj mu nazwę ImageList.json
. Wklej następujące dane do pliku 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
}
]
Skorzystaj z poniższego przykładu roboczego:
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()
}
}
Szczegółowe wyjaśnienie
Utworzony plik json jest częścią pakietu. Aby uzyskać dostęp do tego pliku, możesz utworzyć adres URL wskazujący na niego za pomocą:
Bundle.main.url(forResource: "ImageList", withExtension: "json")
Teraz utwórz zadanie, które będzie działać asynchronicznie w tle z
DispatchQueue.global(qos: .background).async { }
W ramach tego zadania zdekoduj nieprzetworzone dane z pliku json do tablicy struktury ImageSpecification
. Ta struktura opisuje, jak wygląda pojedynczy element. Zgodność z protokołem Codable
umożliwia korzystanie z JSONDecoder
.
Wszelkie aktualizacje na ekranie należy wykonać w głównym wątku. Dlatego musisz upewnić się, że nowe elementy są umieszczane w magazynie w głównym wątku, używając nowej kolejki:
DispatchQueue.main.async { }
W widoku możesz teraz używać swojej DataModel
klasy, która ładuje dane podczas inicjalizacji. Wewnątrz LazyVGrid
, ForEach
widok służy do zapętlania danych. Ponieważ ForEach
oczekuje identyfikatora, który można skasować, albo ustaw całą strukturę zgodnie z Hashable
protokołem, albo wskaż unikalny identyfikator. Nie ma potrzeby podawania niepotrzebnego identyfikatora w pliku json, ponieważ identyfikator jest inicjowany automatycznie. Musisz jednak podać klucze kodowania, aby zapobiec ostrzeżeniom kompilatora (patrz tutaj ).