1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Xcode/SwiftUI】SwiftUI × JSONのポケモンリスト模写してみた

Posted at

こんにちは!今日は多くの人がされているポケモンのリスト作成をやってみました。
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に入れます。

image.png

ファイルの作成

次にファイルを3つ作成します

Pokemon.swift [Model]
PokemonView.swift [View]
PokemonViewModel.swift [ViewModel]

そしてContentViewを消してAppファイルのWindowGroupをPokemonViewに変更しましょう
image.png

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()
    }
}

これでビルドするとアプリが完成するはずです。

完成形

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?