この記事では、SwiftUIでのFSCalendarの実装方法を紹介します。
実装例として、イベントがある日へのマーキング表示と選択されている日の表示方法を解説します。
◆動作検証環境
・XCode:12.3
・SwiftUI:2.0
・iOS:14.0
・LifeCycle:SwiftUI App・FSCalendar:2.8.2
FSCalendarのインストール
FSCalendarのインストールの方法や、実装できるグラフの使用例等はこちらのサイトで確認できます。
今回は、CocoaPodsを利用してFSCalendarのインストールを行います。
CocoaPodsのインストール
まずは下記のコマンドを実行してCocoaPodsをインストールします。
※すでにインストール済みの場合は、こちらの設定は必要ありません。
1 2 3 | sudo gem install cocoapods |
インストールが終わったら、次のコマンドで初期化を行います。
1 2 3 | pod setup |
XcodeプロジェクトへCocoaPodsを導入する
導入の作業の前に、Xcodeのプロジェクトが開かれているか確認します。開いている場合はプロジェクトを閉じます。
プロジェクトディレクトリへの移動
1 2 3 | cd xcode_project |
CocoaPodsファイルの作成
1 2 3 | pod init |
Podfileの編集(Chartsの導入)
さきほどのpod init を行ったディレクトリにPodfile が作成されるので、内容を下記のように編集します。
1 2 3 4 5 6 7 8 9 10 11 12 13 | # Uncomment the next line to define a global platform for your project # platform :ios, '9.0' target 'YourApp' do # Comment the next line if you don't want to use dynamic frameworks use_frameworks! # Pods for YourApp pod 'FSCalendar' #追加 end |
編集後に下記コマンドでFSCalendar のインストールを行います。
1 2 3 | pod install |
インストール後の更新作業は下記コマンドで行います。
1 2 3 | pod update |
対象のモジュールのインストール後からは、ProjectName.xcworkspace で作業、編集を行います(ProjectName.xcodeproj ではない。)
FSCalendarを使ってカレンダーの表示
プロジェクトにFSCalendar の導入ができましたので、まずは基本となるカレンダーの表示を行います。
CalendarView.swiftファイルを作成し、下記のように編集します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import SwiftUI import FSCalendar struct CalendarTestView: UIViewRepresentable { func makeUIView(context: Context) -> UIView { typealias UIViewType = FSCalendar let fsCalendar = FSCalendar() return fsCalendar } func updateUIView(_ uiView: UIView, context: Context) { } } |
高さを指定してこちらのStructを呼びます
1 2 3 4 | CalendarTestView() .frame(height: 400) |
現在の段階で実行すると以下のように表示され、本日の表示、各日付の選択、前月、翌月へのページネーションができます。
FSCalendarを使ったカレンダー表示のカスタマイズ
makeUIView() メソッドに以下のコードを追加してカスタマイズを行います。
紹介している内容以外にも、カスタマイズの方法がありますのでサイトを参考にしてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | //カスタマイズ //表示 fsCalendar.scrollDirection = .vertical //スクロールの方向 fsCalendar.scope = .month //表示の単位(週単位 or 月単位) fsCalendar.locale = Locale(identifier: "en") //表示の言語の設置(日本語表示の場合は"ja") //ヘッダー fsCalendar.appearance.headerTitleFont = UIFont.systemFont(ofSize: 20) //ヘッダーテキストサイズ fsCalendar.appearance.headerDateFormat = "yyyy/MM" //ヘッダー表示のフォーマット fsCalendar.appearance.headerTitleColor = UIColor.label //ヘッダーテキストカラー fsCalendar.appearance.headerMinimumDissolvedAlpha = 0 //前月、翌月表示のアルファ量(0で非表示) //曜日表示 fsCalendar.appearance.weekdayFont = UIFont.systemFont(ofSize: 20) //曜日表示のテキストサイズ fsCalendar.appearance.weekdayTextColor = .darkGray //曜日表示のテキストカラー fsCalendar.appearance.titleWeekendColor = .red //週末(土、日曜の日付表示カラー) //カレンダー日付表示 fsCalendar.appearance.titleFont = UIFont.systemFont(ofSize: 16) //日付のテキストサイズ fsCalendar.appearance.titleFont = UIFont.systemFont(ofSize: 16, weight: UIFont.Weight.bold) //日付のテキスト、ウェイトサイズ fsCalendar.appearance.todayColor = .clear //本日の選択カラー fsCalendar.appearance.titleTodayColor = .orange //本日のテキストカラー fsCalendar.appearance.selectionColor = .clear //選択した日付のカラー fsCalendar.appearance.borderSelectionColor = .blue //選択した日付のボーダーカラー fsCalendar.appearance.titleSelectionColor = .black //選択した日付のテキストカラー fsCalendar.appearance.borderRadius = 0 //本日・選択日の塗りつぶし角丸量 |
上記のように編集し実行すると、下記のような表示となります。
FSCalendarカレンダーでイベント日表示と選択日表示の実装
次に、カレンダー表示でよく利用される、イベントがある日付にドットの表示、さらにユーザーが選択した日付に関連した表示等を行えるようにコードを編集します。
Coordinatorクラスの作成と利用
今回はSwiftUIのプロジェクト内でFSCalendarを利用するので、対応するためにCoordinatorクラスの作成、利用のための実装を行います。
UIKitのインポート、CalendarTestView内に、Coordinatorクラス、makeCoordinatorメソッドの作成、makeUIView内にdelegate、dataSourceの定義を行います。
1 2 3 4 5 6 7 8 9 | class Coordinator: NSObject, FSCalendarDelegate, FSCalendarDataSource { var parent:CalendarTestView init(_ parent:CalendarTestView){ self.parent = parent } } |
1 2 3 4 5 | func makeCoordinator() -> Coordinator{ return Coordinator(self) } |
1 2 3 4 5 6 7 8 9 10 11 12 | func makeUIView(context: Context) -> UIView { typealias UIViewType = FSCalendar let fsCalendar = FSCalendar() fsCalendar.delegate = context.coordinator fsCalendar.dataSource = context.coordinator ... |
これで現在までのCalendarTestViewを含むファイル全コードは以下の内容となります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | import SwiftUI import FSCalendar import UIKit struct CalendarTestView: UIViewRepresentable { func makeUIView(context: Context) -> UIView { typealias UIViewType = FSCalendar let fsCalendar = FSCalendar() fsCalendar.delegate = context.coordinator fsCalendar.dataSource = context.coordinator //カスタマイズ //表示 fsCalendar.scrollDirection = .vertical //スクロールの方向 fsCalendar.scope = .month //表示の単位(週単位 or 月単位) fsCalendar.locale = Locale(identifier: "en") //表示の言語の設置(日本語表示の場合は"ja") //ヘッダー fsCalendar.appearance.headerTitleFont = UIFont.systemFont(ofSize: 20) //ヘッダーテキストサイズ fsCalendar.appearance.headerDateFormat = "yyyy/MM" //ヘッダー表示のフォーマット fsCalendar.appearance.headerTitleColor = UIColor.label //ヘッダーテキストカラー fsCalendar.appearance.headerMinimumDissolvedAlpha = 0 //前月、翌月表示のアルファ量(0で非表示) //曜日表示 fsCalendar.appearance.weekdayFont = UIFont.systemFont(ofSize: 20) //曜日表示のテキストサイズ fsCalendar.appearance.weekdayTextColor = .darkGray //曜日表示のテキストカラー fsCalendar.appearance.titleWeekendColor = .red //週末(土、日曜の日付表示カラー) //カレンダー日付表示 fsCalendar.appearance.titleFont = UIFont.systemFont(ofSize: 16) //日付のテキストサイズ fsCalendar.appearance.titleFont = UIFont.systemFont(ofSize: 16, weight: UIFont.Weight.bold) //日付のテキスト、ウェイトサイズ fsCalendar.appearance.todayColor = .clear //本日の選択カラー fsCalendar.appearance.titleTodayColor = .orange //本日のテキストカラー fsCalendar.appearance.selectionColor = .clear //選択した日付のカラー fsCalendar.appearance.borderSelectionColor = .blue //選択した日付のボーダーカラー fsCalendar.appearance.titleSelectionColor = .black //選択した日付のテキストカラー fsCalendar.appearance.borderRadius = 0 //本日・選択日の塗りつぶし角丸量 return fsCalendar } func updateUIView(_ uiView: UIView, context: Context) { } func makeCoordinator() -> Coordinator{ return Coordinator(self) } class Coordinator: NSObject, FSCalendarDelegate, FSCalendarDataSource { var parent:CalendarTestView init(_ parent:CalendarTestView){ self.parent = parent } } } |
ビルドしてエラーが無い事を確認します。
選択日表示の実装
カレンダー上から選択した日付を表示する機能を実装します。
まずは、CalendarTestView の表示先に、Date 型のState 変数(CalendarTestView でBinding する)を定義し、それを表示します。
1 2 3 4 5 6 7 8 9 10 11 | ... @State var selectedDate = Date() ... CalendarTestView(selectedDate: $selectedDate) .frame(height: 400) Text(selectedDate,style: .date) .font(.title) .padding() ... |
次に、Coordinatorクラスにcalendarメソッドを追加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 | class Coordinator: NSObject, FSCalendarDelegate, FSCalendarDataSource { var parent:CalendarTestView init(_ parent:CalendarTestView){ self.parent = parent } func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) { parent.selectedDate = date } } |
これでカレンダー上で選択された日付がTextで表示されます。
イベント日表示の実装
Coordinatorクラスに、calendarメソッドを追加します。
今回の場合は、24-03-2021 の日程にドットを1個表示する実装内容です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | class Coordinator: NSObject, FSCalendarDelegate, FSCalendarDataSource { var parent:CalendarTestView let dateFormatter = DateFormatter() init(_ parent:CalendarTestView){ self.parent = parent } func calendar(_ calendar: FSCalendar, numberOfEventsFor date: Date) -> Int { dateFormatter.dateFormat = "dd-MM-yyyy" guard let eventDate = dateFormatter.date(from: "24-03-2021") else { return 0 } if date.compare(eventDate) == .orderedSame{ return 1 } return 0 } func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) { parent.selectedDate = date } } |
これで以下のように、2021年3月24日にドット表示がされます。
イベントが複数日ある場合
イベントが複数日ある場合以下のように変更します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | class Coordinator: NSObject, FSCalendarDelegate, FSCalendarDataSource { var parent:CalendarTestView let eventsDate = ["02-03-2021","10-03-2021","24-03-2021"] let dateFormatter = DateFormatter() init(_ parent:CalendarTestView){ self.parent = parent } func calendar(_ calendar: FSCalendar, numberOfEventsFor date: Date) -> Int { dateFormatter.dateFormat = "dd-MM-yyyy" for eventDate in eventsDate{ guard let eventDate = dateFormatter.date(from: eventDate) else { return 0 } if date.compare(eventDate) == .orderedSame{ return 1 } } return 0 } } |
イベントの配列がDate型になっている場合は以下のように利用します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | class Coordinator: NSObject, FSCalendarDelegate, FSCalendarDataSource { var parent:CalendarTestView let eventsDate = [ Date(), Calendar.current.date(byAdding: .day, value: +1, to: Date())!, Calendar.current.date(byAdding: .day, value: +5, to: Date())! ] let dateFormatter = DateFormatter() init(_ parent:CalendarTestView){ self.parent = parent } func calendar(_ calendar: FSCalendar, numberOfEventsFor date: Date) -> Int { dateFormatter.dateFormat = "MMM dd, yyyy" for eventDate in eventsDate{ guard let eventDate = dateFormatter.date(from: dateFormatYMD(date: eventDate)) else { return 0 } if date.compare(eventDate) == .orderedSame{ return 1 } } return 0 } func dateFormatYMD(date: Date) -> String { let df = DateFormatter() df.dateStyle = .long df.timeStyle = .none return df.string(from: date) } } |
以上、SwiftUIでのFSCalendarを使った実装例として、イベントがある日へのドットでのマーキング表示と選択されている日の表示方法を解説しました。