こんにちは!前回の記事(SwiftUIでToDoListアプリを作ってみた)https://qiita.com/kenshin_jp_13/items/9d6a8706828cdb856bfb では、タスクの追加・削除・チェック機能を実装しました。
今回はその続きとして、「タスク完了率をグラフで可視化する」機能を追加しました!📊
SwiftUIの Chartsフレームワーク を使って、完了タスクと未完了タスクの割合を円グラフで表示しています。
🎯 今回の目的
完了タスクと未完了タスクの割合を見える化する
モチベーションを上げるために達成感を「数値化」する
SwiftUI Charts の使い方を学ぶ
グラフの中央に完了率を表示して、下には完了数・未完了数などを表示するようにしました。
🧩 Chart.Swiftに構造体を追加
import Foundation
struct TaskStat: Identifiable {
let id = UUID()
let category: String
let count: Int
}
🧩 ListViewModelに統計用プロパティを追加
既存の ListViewModel に、完了・未完了数や完了率を計算するプロパティを追加します。
class ListViewModel: ObservableObject {
var completedCount: Int {
todoList.filter { $0.isChecked }.count
}
var incompletedCount: Int {
todoList.filter { !$0.isChecked }.count
}
var completionRate: Double {
guard !todoList.isEmpty else { return 0 }
return (Double(completedCount) / Double(todoList.count)) * 100
}
var taskStats: [TaskStat] {
[TaskStat(category: "未完了", count: incompletedCount), TaskStat(category: "完了", count: completedCount)]
}
}
これで、どこからでも ListVM.completionRate のように呼び出して統計情報を使えるようになります。
📊 統計画面(ChartView)
新しく ChartView を作成します。
ListViewModel をそのまま受け取ってグラフを描画します。
import SwiftUI
import Charts
struct ChartView: View {
@ObservedObject var ListVM = ListViewModel()
var body: some View {
NavigationStack {
VStack(spacing: 30) {
Text("タスク統計")
.font(.title.bold())
.padding(.top, 20)
Chart {
ForEach(ListVM.taskStats, id: \.category) { stat in
SectorMark(angle: .value("割合", stat.count),
innerRadius: .ratio(0.6),
outerRadius: .ratio(1.0)
)
.foregroundStyle(by: .value("カテゴリ", stat.category))
}
}
.frame(height: 250)
.padding()
VStack(spacing: 12) {
Text("総タスク数:\(ListVM.todoList.count)")
Text("完了タスク数:\(ListVM.completedCount)")
Text("未完了タスク数:\(ListVM.incompletedCount)")
Text("完了率:\(ListVM.completionRate, specifier: "%.1f")%")
}
.font(.headline)
.padding(.bottom, 30)
}
.padding()
.navigationTitle("統計")
.navigationBarTitleDisplayMode(.inline)
}
}
}
🔗 HomeViewからTabViewで統計画面へ遷移
今回はTabViewを使ってListViewとChartViewで分けました。
import SwiftUI
struct HomeView: View {
@State var selectedTab = 1
var body: some View {
TabView(selection: $selectedTab) {
NavigationStack {
ListView()
}
.tabItem {
Label("リスト", systemImage: "list.bullet")
}
.tag(1)
NavigationStack {
ChartView()
}
.tabItem {
Label("グラフ", systemImage: "chart.pie.fill")
}
.tag(2)
}
}
}
✅ 実行結果
タスクを完了にすると、グラフがリアルタイムで更新され、
完了率も自動で変化するようになりました。
「達成率が上がる→モチベーションも上がる」
という最高のループが完成です🔥
✨ まとめ
SwiftUIのChartsを使えば、たった数行でグラフ表示ができる
HomeViewModelを拡張するだけで統計画面がすぐ作れる
見た目と体験の両方が向上する
