このPartでは、リストを使ってなんちゃってToDoリストを作ってみます。
では、実装していきましょう。ToDoList
という名前でプロジェクトを作成してください。
ToDoリスト開発
レイアウト実装
まずは、レイアウトを作っていきましょう。
-
ナビゲーションバーを作る
まずは、ナビゲーションバーを作りましょう。以下のようにVStack
をNavigationStack
で囲ってください。NavigationStack { VStack { Image(systemName: "globe") .imageScale(.large) .foregroundColor(.accentColor) Text("Hello, world!") } .padding() }
追記する場所
-
Listを作る
次にリストを作りましょう。NavigationStack
の中をList
に変更してみましょう。NavigationStack { List { Text("ジョギングする") Text("お花に水をやる") Text("部屋の掃除をする") Text("本を読む") } .navigationTitle("ToDoリスト") }
実行するとこのようなレイアウトになります。追記する場所
-
左側にアイコンをつける
Text
一つ一つをHStack
で囲って、Image
をつけましょう。List { HStack { Image(systemName: "circle") Text("ジョギングする") } HStack { Image(systemName: "checkmark.circle.fill") Text("お花に水をやる") } HStack { Image(systemName: "checkmark.circle.fill") Text("部屋の掃除をする") } HStack { Image(systemName: "circle") Text("本を読む") } }
実行すると、テキストの左側にチェックマークのアイコンが表示されるはずです。追記する場所
これで見た目はToDoリストっぽくなりました。
ForEachを使う
現時点では、List
の中に、4回もHStack
で同じようにセルを記述しています。たくさんのセルを表示するとなると、その度にHStack
を記述するので、かなりコードが長くなってしまいます。
Text
の内容とImage
の名前だけしか変わらないので、その数の分記述するのではなく、その数の分処理を繰り返し行うというふうにしましょう。
そうすると、少ないコードで実装できます。
-
配列を宣言
let taskData = ["ジョギングする", "お花に水をやる", "部屋の掃除をする", "本を読む"]
追記する場所
-
Listの中を変更
List
のなく以下のように変更してください。これでだいぶコードが短くなります。List(0..<taskData.count, id:\.self) { index in HStack { Image(systemName: "circle") Text(taskData[index]) } }
追記する場所
実行して確認してください。一旦アイコンは⚪︎だけになってしまいますが、先ほどと同じようなレイアウトになるはずです。
機能をつける
では、ToDoリストっぽく、ボタンを押したらチェックマークがつくようにしましょう。
-
ボタンを作る
まずは、セルを押せるようにしましょう。以下のようにHStack
をButton
の中に入れましょう。Button { } label: { HStack { Image(systemName: "circle") Text(taskData[index]) } }
このようにセルを押せるようになっているはずです。追記する場所
-
ボタンの文字色を戻す
Button
にしたら文字色が青になってしまったので、以下のモディファイアをつけて黒に戻しましょう。.foregroundColor(.black)
実行して確認してみると黒に戻っているはずです。追記する場所
-
データの構成を変更する
現状のデータは、タスクが終了しているかどうかの値がないため、ボタンを押したらチェックマークがつくという実装ができません。なので、データの構成を変更します。
クラス外に以下のモデルを追加してください。struct TaskData: Identifiable { var title: String var completed: Bool var id = UUID() }
追記する場所
-
taskDataを変更
taskData
を以下のように変更してください。(現時点ではエラーになります。)@State var taskData = [ TaskData(title: "ジョギングする", completed: false), TaskData(title: "お花に水をやる", completed: false), TaskData(title: "部屋の掃除をする", completed: false), TaskData(title: "本を読む", completed: false) ]
追記する場所
-
エラーの修正
データの構成を変更したので、Text(taskData[index])
のところでエラーになっています。以下のように変更してください。Text(taskData[index].title)
追記する場所
-
Imageを変更
もし、completed
がfalse
だったら◯で、true
だったら☑️にしましょう。Image
の部分を以下のように変更してください。if taskData[index].completed { Image(systemName: "checkmark.circle.fill") } else { Image(systemName: "circle") }
追記する場所
-
三項演算子に変更
このくらいのif文なら、三項演算子を使った方が良いです。Image
のif文を以下のように変更しましょう。Image(systemName: taskData[index].completed ? "checkmark.circle.fill" : "circle")
追記する場所
-
ボタンを押したらcompletedを変更
ボタンを押したら、completed
の値を変更するようにしましょう。Button { taskData[index].completed.toggle() } label: {
実行して確認しましょう。追記する場所
セルを押すとチェックマークが付いて、もう一度押すとチェックマークが外れるようになると思います。
バグ修正
シミュレーターをダークモードにしたら、黒背景に黒文字になってしまい、文字が読みづらくなってしまいました。
ダークモードにする方法としては、シミュレーターでcommand + shift + aを押すか、
ホーム画面に戻って設定 > デベロッパ > ダークの外観モードをONにするとダークモードになります。
ボタンに対して、.foregroundColor(.black)
というモディファイアをつけたので、強制的に黒になってしまいます。
黒色に黒は見づらいので、ダークモードの時は白色で、ライトモードの時は黒色にしたいです。
なので、以下のように変更してみましょう。.black
ではなく、以下のように、.primary
にしましょう。
.foregroundColor(.primary)
追記する場所
これで、ダークモードで実行すると白色になって、ライトモードで実行すると黒色になります。
これで、なんちゃってToDoが完成しました!
ここから、ToDoの入力フォームを作って、データを保存できるようにすれば本格的なToDoになると思います!
全てのコード
全てのコード
import SwiftUI
struct TaskData: Identifiable {
var title: String
var completed: Bool
var id = UUID()
}
struct ContentView: View {
@State var taskData = [
TaskData(title: "ジョギングする", completed: false),
TaskData(title: "お花に水をやる", completed: false),
TaskData(title: "部屋の掃除をする", completed: false),
TaskData(title: "本を読む", completed: false)
]
var body: some View {
NavigationStack {
List(0..<taskData.count, id:\.self) { index in
Button {
taskData[index].completed.toggle()
} label: {
HStack {
Image(systemName: taskData[index].completed ? "checkmark.circle.fill" : "circle")
Text(taskData[index].title)
}
}
.foregroundColor(.primary)
}
.navigationTitle("ToDoリスト")
}
}
}