【SwiftUI】pickerの選択肢ごとに色を変えたかった

あまりプログラミングをしないエンジニアなのですが、SwiftUIが良さそうというのを聞いたので最近趣味感覚で書いています。

今回はpickerの選択肢ごとに色を変えたかったのでやってみました。

完成形はこんな感じです。

f:id:disuke:20201216225918p:plain

どうやるかなのですが、今回はjsonファイルで色を設定してみました。(もっと良い方法あるかもしれないです。。)

まずこんな感じのjsonファイルを用意します。idとname以外は色の設定値です。 ファイル名はAlphabets.jsonにします

{
    "alphabets":[
        {
            "id": 1,
            "name": "A",
            "hue": 0.476,
            "saturation": 0.075,
            "brightness": 0.041,
            "opacity": 0.227
        },
        {
            "id": 2,
            "name": "B",
            "hue": 0.476,
            "saturation": 0.78,
            "brightness": 0.929,
            "opacity": 0.532
        },
        {
            "id": 3,
            "name": "C",
            "hue": 0.32,
            "saturation": 0.751,
            "brightness": 0.565,
            "opacity": 0.962
        },
        {
            "id": 4,
            "name": "D",
            "hue": 0.845,
            "saturation": 0.961,
            "brightness": 0.952,
            "opacity": 0.962
        },
        {
            "id": 5,
            "name": "E",
            "hue": 0.177,
            "saturation": 0.921,
            "brightness": 0.977,
            "opacity": 0.962
        },

次はjsonデータをデコードします。

新たに下記のswiftファイルを作成します。

import Foundation

let mojis:[Alphabet] = getJson()

struct Mojis: Codable {
    var alphabets: [Alphabet]
    
}

struct Alphabet: Codable {
    var id: Int
    var name: String
    var hue: Double
    var saturation: Double
    var brightness: Double
    var opacity: Double
}

func getJson() -> [Alphabet] {
    guard let path = Bundle.main.path(
        forResource: "Alphabets", 
        ofType: "json") 
    else {
        fatalError("Couldn't find json file")
    }
    let url = URL(fileURLWithPath: path)
    
    guard let json = try? Data(contentsOf: url) 
    else {
        fatalError("parse error")
    }
    
    let decoder = JSONDecoder()
    let decodeData: Mojis
    do {
        decodeData = try decoder.decode(Mojis.self, from: json)
    }
    catch {
        fatalError("decode error")
    }
    return decodeData.alphabets
}

何をしているかというと まず、上の2つのstructはjsonファイルに合わせて作成します

そして次に、下記の様にjsonファイルを読み込んでいます

guard let path = Bundle.main.path(
        forResource: "Alphabets", 
        ofType: "json") 

次にjsonデータをデコードしています

guard let json = try? Data(contentsOf: url) 
    else {
        fatalError("parse error")
    }
    
    let decoder = JSONDecoder()
    let decodeData: Mojis
    do {
        decodeData = try decoder.decode(Mojis.self, from: json)
    }
    catch {
        fatalError("decode error")
    }

これでデータを加工できたので、次に表示していきます。

XcodeでSwiftUIのプロダクトを作成するとContentView.swiftファイルが作成されていると思うので、そこを編集していきます。
最初はこの様な感じになっています。 f:id:disuke:20201216231941p:plain ContentView.swift

なので下記の様に修正しました

import SwiftUI

struct ContentView: View {

    @State private var selected = ""

    var body: some View {
        VStack {
            Picker(selection: $selected, label: Text("アルファベット")) {
                ForEach(0..<15) { num in
                    Text(mojis[num].name)
                            .font(.body)
                        .frame(width: 200.0, height: 20.0)
                        .background(Color(
                             hue: mojis[num].hue, 
                             saturation: mojis[num].saturation, 
                             brightness: mojis[num].brightness, 
                             opacity: mojis[num].opacity))
                        .tag(mojis[num].name)
                }
            }
            Text("選択した文字: \(selected)")
        }
    }

この@Stateをつけると値を監視して、変更されると更新してくれます

@State private var selected = ""

そしてあとはPickerの使い方ですがこちらのサイトを参考にしました。

capibara1969.com

こんな感じで作成しました。

説明が雑になってしまったのですが、アドベントカレンダーで今日までということを忘れていました。。
SwiftUIは書いてて楽しいので、また書いていきたいです!

ちなみにこちらの本を参考にしました。

SwiftUIではじめるiPhoneアプリプログラミング入門 | 大津 真 |本 | 通販 | Amazon

それでは〜