はじめに

こんにちは。エンジニアの荒井です。
今回は初めてSwiftUIを使ってアプリを作成してみたという記事です。

アプリ作成の前段階として、Apple公式のSwiftUIチュートリアルだけやりました。
(ただもちろんそれだけではわからないことだらけだったので、都度調べています)

作ったアプリの概要・背景

毎日使っているけど何個使っているのかわからないものや、たまにするけどそれが毎日/毎月結局何回なのかわからない行動など、うっすらわかるけど記録はしていないことってありませんか?
紙のカレンダーや紙の手帳に正の字書いて管理していたけど今は使っていないから管理していない!なんていうこともあるのではないでしょうか。

  • いいことあったなと思った回数
  • 頭痛薬を飲んだ回数
  • 飲んだコーヒーの杯数
  • 食べたチョコの個数

などなど、記録してみると便利/面白い自分の傾向ってあるよなあと思います。
そこで、アプリを開いて日付をタップするだけカウントできるという、ミニマムアクションのアプリを作ってみました。

要件

  • アプリ起動後の初期表示はデフォルトカレンダー
  • カレンダーは月表示
  • 現在の日付が分かるように背景色を付ける
  • 各日付をタップするとカウントが1ずつ加算される
  • データはアプリ内のローカルストレージで保持する
  • カウントされた数字は各日付の枠内に表示する

実際に作ってみる

開発環境

macOS 15.0.1
Xcode Version 16.1

実行環境

シミュレータ (iPhone 16 Pro/iOS 18.1)

Githubリポジトリ

作成したアプリのコードは以下のリポジトリに格納しております。
https://github.com/milldea/blog-count-per-day-app

フェーズ1

まずは、カレンダーを表示するのを目標にしました。

  • アプリ起動後の初期表示はデフォルトカレンダー
  • カレンダーは月表示
  • 現在の日付が分かるように背景色を付ける

この部分です。

実装

今回はContentViewに全てを詰め込みました。
フルのコードはこちらを参照ください。

大まかな流れとポイントは以下です。

  • 当日をcurrentDateとして持ち、初期表示の月を決める
  • 7日×6週で日付のセルを用意する
  • currentDateの月の1日が何曜日から始まるのかを判定し、順にセルに日付を入れていく
    • 当日の日付である場合は描画の際に背景色・文字色を変更する
  • 前月・次月を表示するボタンを用意し、押下された際はcurrentDateの月を +1, -1 する

こう書いてみると単純な話なのですが、細かいところに結構苦戦しました。。

実際の画面

とりあえずそれっぽい見た目にはなったかな、というところでしょうか。 MAX6行、MIN4行なのでどう表示するかは悩んだのですが、月の切り替え時に描画スペースが変わると遷移がガチャガチャするので常に6行表示です。

フェーズ2

次に、カウント機能をつけていきます。

  • 各日付をタップするとカウントが1ずつ加算される
  • データはアプリ内のローカルストレージで保持する
  • カウントされた数字は各日付の枠内に表示する

この部分です。

実装

ポイントは以下です。

  • 日付をタップしてカウント追加:タップイベントを検出し、その日付のカウントを増やす
  • カウントデータの保存と取得:日付をキーにしてカウントを保存する
  • カウントの表示:セルの右下にカウントを表示する

フルのコードはこちらを参照ください。

画面

15日のセルを一回タップした後の表示です。

日付よりもカウントを大きく表示したので、このアプリがカウンターである主張が強いですね。

おわりに

今回アプリを作ってみて思ったことをまとめます。
まず、SwiftUIの感想です。

  • ローカルストレージの使い方が簡単すぎる!楽しい!
  • スタックの並べ方や描画のプロパティ設定の仕方はチュートリアルでやったことがとっても活きる
  • (でもGUIベースでUIを触るのは便利だけど実際にアプリを作り始めるとあまり使わないかも...)

次に、このアプリについて改良の余地がありそうなところです。

  • 間違えてタップした時のためにカウントを減らす操作ができると良い
  • カレンダーを複数持ちたい
  • データをCSV出力したい

最後に雑感です。
実は、こんなミニマムなアプリで解説するようなところもほとんどないのに意外と手こずりました。。
普段触らない言語を触ってみると なんとなく何を書けば良いか分かっているのに書けない、エラーになる という、妙に脳に負荷のかかる詰まり方をしますね。
結構疲れましたが、それ以上に面白かったです。
引き続きこのアプリの改良をしてみようと思います!