3
2

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.

Qiita全国学生対抗戦Advent Calendar 2023

Day 17

【SwiftUI】Chartsをまだ使ったことがなかったので株価アプリのUIっぽいの作って入門してみた1

Last updated at Posted at 2023-12-17

はじめに

iOS16から使えるようになったChartsをまだ使ったことがなかったので、iPhoneに標準で入ってる株価アプリのUIっぽい感じのものを作ってみました。
ほぼ同じのクローンみたいなの作ろうと思ったんですけど、難易度高くて諦めました。

サンプルアプリ

今回作ったのはこんな感じ
simulator_screenshot_F5254B35-F7E3-435F-BF3F-E81A558ED637.png

本当はタップした日時の株価が表示されたらいい感じだったんですけど、むずくて断念しました。
そのうちやります。

準備

今回、日付を扱うので軽くDate拡張を作成しました。
これはメインではないので適当な感じです。

extension Date {
    init(year: Int, month: Int, day: Int) {
        let calendar = Calendar(identifier: .gregorian)

        var components = DateComponents()
        components.year = year
        components.month = month
        components.day = day

        self = calendar.date(from: components)!
    }
}

モデルの用意

struct Stock: Identifiable {
    var id = UUID()
    var date: Date
    var value: Int
}

実装

import Charts
import SwiftUI

struct ContentView: View {
    @State private var stocks: [Stock] = [
        .init(date: .init(year: 2023, month: 10, day: 2), value: 2130),
        .init(date: .init(year: 2023, month: 10, day: 3), value: 4160),
        .init(date: .init(year: 2023, month: 10, day: 4), value: 4308),
        .init(date: .init(year: 2023, month: 10, day: 5), value: 5220),
        .init(date: .init(year: 2023, month: 10, day: 6), value: 6311),
        .init(date: .init(year: 2023, month: 10, day: 10), value: 6311),
        .init(date: .init(year: 2023, month: 10, day: 11), value: 5809),
        .init(date: .init(year: 2023, month: 10, day: 12), value: 5350),
        .init(date: .init(year: 2023, month: 10, day: 13), value: 5196),
        .init(date: .init(year: 2023, month: 10, day: 16), value: 5200),
        .init(date: .init(year: 2023, month: 10, day: 17), value: 6123),
        .init(date: .init(year: 2023, month: 10, day: 18), value: 6110),
        .init(date: .init(year: 2023, month: 10, day: 19), value: 6092),
        .init(date: .init(year: 2023, month: 10, day: 20), value: 6501),
        .init(date: .init(year: 2023, month: 10, day: 23), value: 6867),
        .init(date: .init(year: 2023, month: 10, day: 24), value: 7381),
        .init(date: .init(year: 2023, month: 10, day: 25), value: 7980),
        .init(date: .init(year: 2023, month: 10, day: 26), value: 9016),
        .init(date: .init(year: 2023, month: 10, day: 27), value: 8221),
        .init(date: .init(year: 2023, month: 10, day: 30), value: 7217),
        .init(date: .init(year: 2023, month: 10, day: 31), value: 6221),
    ]

    var body: some View {
        Chart {
            ForEach(stocks, id: \.id) { stock in
                AreaMark(
                    x: .value("日時", stock.date, unit: .day, calendar: .autoupdatingCurrent),
                    y: .value("株価", stock.value)
                )
                .foregroundStyle(.linearGradient(
                    .init(colors: [.green.opacity(0.3), .green.opacity(0.1)]),
                    startPoint: .top,
                    endPoint: .bottom
                ))

                LineMark(
                    x: .value("日時", stock.date, unit: .day, calendar: .autoupdatingCurrent),
                    y: .value("株価", stock.value)
                )
                .foregroundStyle(.green)
                .symbol(.circle)
            }
        }
        .frame(height: 250)
        .preferredColorScheme(.dark)
    }
}

解説

折れ線グラフはLineMarkです。
foregroundStyleで色を変えることができます。
スクリーンショット 2023-12-17 22.56.03.png

Chart {
    ForEach(stocks, id: \.id) { stock in
+       LineMark(
+           x: .value("日時", stock.date, unit: .day, calendar: .autoupdatingCurrent),
+           y: .value("株価", stock.value)
+       )
        .foregroundStyle(.green)
    }
}

下に向かってグラデーションがかかってるやつはAreaMarkです。
LineMarkAreaMarkを組み合わせて使うことで折れ線グラフの下を塗りつぶすことができます。
こちらもforegroundStyleで色を変えることができます。
スクリーンショット 2023-12-17 22.56.49.png

Chart {
    ForEach(stocks, id: \.id) { stock in
+       AreaMark(
+           x: .value("日時", stock.date, unit: .day, calendar: .autoupdatingCurrent),
+           y: .value("株価", stock.value)
+       )
        .foregroundStyle(.linearGradient(
            .init(colors: [.green.opacity(0.3), .green.opacity(0.1)]),
            startPoint: .top,
            endPoint: .bottom
        ))
    }
}

symbolを使用することによって、折れ線グラフの値のある位置にViewを配置することができます。
スクリーンショット 2023-12-17 22.59.02.png

Chart {
    ForEach(stocks, id: \.id) { stock in
        LineMark(
            x: .value("日時", stock.date, unit: .day, calendar: .autoupdatingCurrent),
            y: .value("株価", stock.value)
        )
        .foregroundStyle(.green)
+       .symbol(.circle)
    }
}

おわり

次回はChartsにアニメーションとか付けてみたいですね

3
2
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
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?