こんにちは!今日は多くの人がされているポケモンのリスト作成をやってみました。
JSONファイルを作成しそのJSONファイルをもとにポケモンのリストを表示するというアプリになります。
簡単でまたとても楽しかったのでぜひ作られてみてください。
アプリの構成はMVVMアーキテクチャで作成します。
まずは完成系がこちら!!
なんかいい感じですね。
では作り方です。
まずはJSONファイルを作成します。私はJSON Online Editorを使ってファイルを作成しました。
https://jsoneditoronline.org/
pokemon.json
{
"pokemon": [
{
"id": 1,
"name": "Bulbasaur",
"types": ["Grass", "Poison"],
"description": "A strange seed was planted on its back at birth. The plant sprouts and grows with this Pokémon.",
"image_url": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png"
},
{
"id": 2,
"name": "Charmander",
"types": ["Fire"],
"description": "Obviously prefers hot places. When it rains, steam is said to spout from the tip of its tail.",
"image_url": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/4.png"
},
{
"id": 3,
"name": "Squirtle",
"types": ["Water"],
"description": "After birth, its back swells and hardens into a shell. Powerfully sprays foam from its mouth.",
"image_url": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/7.png"
},
{
"id": 4,
"name": "Pikachu",
"types": ["Electric"],
"description": "When several of these Pokémon gather, their electricity could build and cause lightning storms.",
"image_url": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/25.png"
},
{
"id": 5,
"name": "Eevee",
"types": ["Normal"],
"description": "Its genetic code is irregular. It may mutate if it is exposed to radiation from element Stones.",
"image_url": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/133.png"
},
{
"id": 6,
"name": "Mew",
"types": ["Psychic"],
"description": "So rare that it is still said to be a mirage by many experts. Only a few people have seen it worldwide.",
"image_url": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/151.png"
},
{
"id": 7,
"name": "Gengar",
"types": ["Ghost", "Poison"],
"description": "Under a full moon, this Pokémon likes to mimic the shadows of people and laugh at their fright.",
"image_url": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/94.png"
},
{
"id": 8,
"name": "Dragonite",
"types": ["Dragon", "Flying"],
"description": "This Pokémon is so strong, it can easily hold aloft a child while flying.",
"image_url": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/149.png"
},
{
"id": 9,
"name": "Mewtwo",
"types": ["Psychic"],
"description": "It was created by a scientist after years of horrific gene-splicing and DNA-engineering experiments.",
"image_url": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/150.png"
},
{
"id": 10,
"name": "Sylveon",
"types": ["Fairy"],
"description": "It sends a soothing",
"image_url": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/700.png"
}
]
}
この作成したファイルをXcodeに入れます。
ファイルの作成
次にファイルを3つ作成します
Pokemon.swift [Model]
PokemonView.swift [View]
PokemonViewModel.swift [ViewModel]
そしてContentViewを消してAppファイルのWindowGroupをPokemonViewに変更しましょう
Model
Pokemon.swift
import Foundation
struct PokemonResponse: Codable {
let pokemon: [Pokemon]
}
struct Pokemon: Codable, Hashable {
let id: Int
let name: String
let types: [String]
let description: String
let imageUrl: URL
enum CodingKeys: String, CodingKey {
case id
case name
case types
case description
case imageUrl = "image_url"
}
}
ViewModel
import Foundation
class PokemonViewModel: ObservableObject {
@Published var pokemon: [Pokemon] = []
func fetchPokemon() {
guard let url = Bundle.main.url(forResource: "pokemon", withExtension: "json") else {
print("File not Found")
return
}
let task = URLSession.shared.dataTask(with: url) { data, _, error in
if let data = data {
if let decodedData = try? JSONDecoder().decode(PokemonResponse.self, from: data) {
DispatchQueue.main.async {
self.pokemon = decodedData.pokemon
}
}
}
}
task.resume()
}
}
View
import SwiftUI
struct PokemonView: View {
@ObservedObject private var viewModel = PokemonViewModel()
var body: some View {
List(viewModel.pokemon, id: \.self) { pokemon in
pokemonDataList(pokemon)
}
.onAppear {
viewModel.fetchPokemon()
}
}
}
@ViewBuilder
private func pokemonDataList(_ pokemon: Pokemon) -> some View {
HStack {
ZStack {
Circle()
.fill(Color.gray.opacity(0.4))
.frame(width: 80, height: 80)
AsyncImage(url: pokemon.imageUrl) { phase in
switch phase {
case .empty:
ProgressView()
case .success(let image):
image
.resizable()
.frame(width: 80, height: 80)
case .failure:
Text("Failed to load image")
@unknown default:
Text("Unknown error")
}
}
}
VStack(alignment: .leading) {
HStack {
Text(pokemon.name)
.font(.system(size: 24, weight: .light))
Spacer()
Text(pokemon.types.joined(separator: ", "))
.font(.system(size: 16, weight: .light))
.foregroundColor(.black.opacity(0.8))
}
Spacer().frame(height: 4)
Text(pokemon.description)
.foregroundColor(.gray.opacity(0.8))
.font(.system(size: 12, weight: .light))
}
}
}
struct PokemonView_Previews: PreviewProvider {
static var previews: some View {
PokemonView()
}
}
これでビルドするとアプリが完成するはずです。