はじめに
昨日、株価アプリの見た目を作成しました。
この記事は前回の記事から続いています。
今回は株価をタップ&ドラッグした時のアクションを追加してみます。
実際の株価アプリ
作成したサンプルアプリ
選択するとグラフが青くなり、選択している日付に縦線が表示されます。
準備
前回のDate拡張と同様
モデルの用意
前回のモデルと同様
実装
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),
]
// 選択している日付
@State private var selectedDate: Date?
// チャートの色
private var chartColor: Color {
selectedDate != nil ? .cyan : .green
}
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: [chartColor.opacity(0.3), chartColor.opacity(0.1)]),
startPoint: .top,
endPoint: .bottom
))
LineMark(
x: .value("日時", stock.date, unit: .day, calendar: .autoupdatingCurrent),
y: .value("株価", stock.value)
)
.foregroundStyle(chartColor)
if let selectedDate {
// これが日付を選択した時に出てくる縦線
RuleMark(
x: .value("株価", selectedDate)
)
.foregroundStyle(chartColor)
}
}
}
.frame(height: 250)
.chartXSelection(value: $selectedDate)
.chartGesture { chart in
DragGesture(minimumDistance: 0)
.onChanged {
// ドラッグしている座標をチャートに知らせる
chart.selectXValue(at: $0.location.x)
}
.onEnded { _ in
// 指を離した時にselectedDateをリセット
selectedDate = nil
}
}
.preferredColorScheme(.dark)
}
}
解説
指が触れている日付を格納する変数を作成します。
// 選択している日付
@State private var selectedDate: Date?
以下の2つはセットです。
chartXSelection
で先ほど作った変数に日付を格納しています。
chart.selectXValue(at:)
が実行されると、chartXSelection
が発火してselectedDate
に値が入ります
指を離したら元に戻って欲しいのでonEnded
でnil
にします。
.chartXSelection(value: $selectedDate)
.chartGesture { chart in
DragGesture(minimumDistance: 0)
.onChanged {
// ドラッグしている座標をチャートに知らせる
chart.selectXValue(at: $0.location.x)
}
.onEnded { _ in
// 指を離した時にselectedDateをリセット
selectedDate = nil
}
}
selectedDate
がnil
じゃなければ、選択している日付に縦線を表示します。
if let selectedDate {
// これが日付を選択した時に出てくる縦線
RuleMark(
x: .value("株価", selectedDate)
)
.foregroundStyle(chartColor)
}
おわり
Charts用のモディファイアがいっぱいですね。
参考記事