FSCalendarのカレンダー表示モードを変更する

#はじめに
カレンダー付きToDoアプリを制作する際にFSCalendarというライブラリを使用しましたので備忘録として投稿します。
初学者ですので訂正点ございましたら、ご指摘よろしくお願いします。


#概要
FSCalendarではカレンダーの表示モードを`月表示`や`週表示`に任意で変更することができます。
制作したアプリの用途に絡めると「ボタンのタップイベントにて表示モードを変更する」になります。

また、FSCalendarの導入に関しましては[こちら](https://github.com/WenchaoD/FSCalendar)を参照ください。


#実行環境
【Xcode】 Version 11.7
【Swift】 version 5.2.4
【CocoaPods】version 1.9.3
【FSCalendar】version 2.8.1


#実装後の画面
![sample.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692635/9fc8d6cd-b41d-1d5d-1491-5278f1daf580.gif)


#実装コード
全体のコードになります。
サンプルコードではなく、自作アプリのコードになりますので関連箇所を抜粋しております。
また、FSCalendarのDelegateとDataSourceはstoryboard上で追加しております。

```swift:MainViewController.swift
import UIKit
import FSCalendar
import CalculateCalendarLogic
# ・・・省略・・・

class MainViewController: UIViewController {

    @IBOutlet weak var calendar: FSCalendar!
    @IBOutlet weak var calendarHeight: NSLayoutConstraint!
    # ・・・省略・・・

    override func viewDidLoad() {
        super.viewDidLoad()

        // calendarの曜日部分を日本語表記に変更
        calendar.calendarWeekdayView.weekdayLabels[0].text = "日"
        calendar.calendarWeekdayView.weekdayLabels[1].text = "月"
        calendar.calendarWeekdayView.weekdayLabels[2].text = "火"
        calendar.calendarWeekdayView.weekdayLabels[3].text = "水"
        calendar.calendarWeekdayView.weekdayLabels[4].text = "木"
        calendar.calendarWeekdayView.weekdayLabels[5].text = "金"
        calendar.calendarWeekdayView.weekdayLabels[6].text = "土"
        // calendarの曜日部分の色を変更
        calendar.calendarWeekdayView.weekdayLabels[0].textColor = .systemRed
        calendar.calendarWeekdayView.weekdayLabels[6].textColor = .systemBlue

        # ・・・省略・・・
    }

    // calendarの表示形式変更
    @IBAction func changeButtonAction(_ sender: Any) {
        if calendar.scope == .month {
            calendar.setScope(.week, animated: true)
            changeButton.title = "月表示"
            // calendarを更新
            calendar.reloadData()
        } else if calendar.scope == .week {
            calendar.setScope(.month, animated: true)
            changeButton.title = "週表示"
            // calendarを更新
            calendar.reloadData()
        }         
    }
    # ・・・省略・・・
}

extension MainViewController: FSCalendarDelegate, FSCalendarDataSource, FSCalendarDelegateAppearance {
    # ・・・省略・・・
    func calendar(_ calendar: FSCalendar, boundingRectWillChange bounds: CGRect, animated: Bool) {
        calendarHeight.constant = bounds.height
        self.view.layoutIfNeeded()
    }
    # ・・・省略・・・
}
```


#実装方法（storyboardにて）
####１．storyboardに`FSCalendar`を配置する
- 配置方法の手順は[こちら](https://qiita.com/Koutya/items/f5c7c12ab1458b6addcd)を参照下さい。

####２．配置した`FSCalendar`にAutoLayoutの制約を付ける
- `上`と`左右`に`0`を設定します。（※１）
- `Height`を設定します。今回は`350`にしました。この制約が大切なので忘れずに設定して下さい。（※２）
- `Constraint to margins`にチェックが入っていると、余計な`margin`が入ってしまうので外しておきましょう。（※３）

![スクリーンショット 2020-09-16 23.58.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692635/9b8d5beb-fa64-d6f6-03a3-1610f6101106.png)


#実装方法（コードにて）
####１．`FSCalendar`クラスの`calendar`を定義し、storyboardで紐づけする
```swift:
@IBOutlet weak var calendar: FSCalendar!
```

####２．`NSLayoutConstraint`クラスの`calendarHeight`を定義する
- コードでAutoLayoutの制約を付ける場合、`NSLayoutConstraint`クラスによって定義することができます。

```swift:
@IBOutlet weak var calendarHeight: NSLayoutConstraint!
```

####３．AutoLayoutで制約の設定をした`Height`と２．で定義した`calendarHeight`をstoryboardで紐づけする
- 添付写真は`calendar Height`と紐づけされた後の表記になっております。紐付ける前は`height = 350`となります。

![スクリーンショット 2020-09-17 0.28.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692635/51c91952-e40a-8d3b-63cf-7763ad8ded5f.png)

####４．ボタンのタップイベントでカレンダーの表示モードを変更する
- 以下のコードを用いることで表示モードを変更することができます。

```swift:
//月ごとの表示にしたい時         
calendar.setScope(.month, animated: true)
//週ごとの表示にしたい時
calendar.setScope(.week, animated: true)
```

- 上記をボタンのタップイベントに絡めていきます。説明が抜けておりますが`changeButtonAction`は「実装後の画面」で操作しているボタンになります。

```swift:
// calendarの表示形式変更
@IBAction func changeButtonAction(_ sender: Any) {
    if calendar.scope == .month {
        calendar.setScope(.week, animated: true)
        changeButton.title = "月表示"
        // calendarを更新
        calendar.reloadData()
    } else if calendar.scope == .week {
        calendar.setScope(.month, animated: true)
        changeButton.title = "週表示"
        // calendarを更新
        calendar.reloadData()
    }         
}
```

####５．Viewの大きさのリサイズ
- FSCalendarは`月表示`が標準で、コードで表示モードを`週表示`に切り替えると、レイアウトの自動調整がかかりません。この問題は下記コードを追加することにより解決することができます。

```swift:
func calendar(_ calendar: FSCalendar, boundingRectWillChange bounds: CGRect, animated: Bool) {
    calendarHeight.constant = bounds.height
    self.view.layoutIfNeeded()
}
```

#補足（カレンダー表示について）
- 週の`表示名`や`色`を変更したい場合は下記コードを追加することで「実装後の画面」のようになります。

```swift:
// calendarの曜日部分を日本語表記に変更
calendar.calendarWeekdayView.weekdayLabels[0].text = "日"
calendar.calendarWeekdayView.weekdayLabels[1].text = "月"
calendar.calendarWeekdayView.weekdayLabels[2].text = "火"
calendar.calendarWeekdayView.weekdayLabels[3].text = "水"
calendar.calendarWeekdayView.weekdayLabels[4].text = "木"
calendar.calendarWeekdayView.weekdayLabels[5].text = "金"
calendar.calendarWeekdayView.weekdayLabels[6].text = "土"
// calendarの曜日部分の色を変更
calendar.calendarWeekdayView.weekdayLabels[0].textColor = .systemRed
calendar.calendarWeekdayView.weekdayLabels[6].textColor = .systemBlue
```

- `日付`のフォーマットはstoryboardで変更することができます。

![スクリーンショット 2020-09-18 21.57.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692635/1af13361-79cd-c21c-bd6e-20f782445895.png)


#参考
- [Swiftで簡単にカレンダーを作ろう！(FSCalendar)](https://qiita.com/Koutya/items/f5c7c12ab1458b6addcd)
- [コードでAutolayout](https://qiita.com/bonegollira/items/5c973206b82f6c4d55ea)
- [UIViewにおけるレイアウトのライフサイクル](https://qiita.com/shoheiyokoyama/items/2f76938dffa845130acc)