iOS12 Swift4 UIPageView＆UICollectionViewでページングCalendarを作る

メイン参考：
@sakuran  https://qiita.com/sakuran/items/3c2c9f22cbcbf4aff731
@BMJr https://qiita.com/BMJr/items/653e8843bf33abd02b9c
@rinov https://qiita.com/rinov/items/bff12e9ea1251e895306
Stanford PaulHegarty https://github.com/JqyModi/cs193p-Winter-2017-Stanford-IOS11-PaulHegarty.git
最近iOSの開発を勉強しているから、いろんな疑問があって、やっとわかた内容を共有したいです。
##考え方
1.アプリ初期化の時、現在の時間の年月の日を表示する、そしてタイトルに和暦年と月を表示する
2.ページを前後に開いてから、前後月の日を表示する、もちろん必要なら年も変える、例えば1月の先月、12月の来月
3.⏪⏩を押したら、前後の年に変える。
![Screen Shot 0031-03-17 at 12.10.26 AM.png](https://qiita-image-store.s3.amazonaws.com/0/369482/5531a6ec-4a11-f154-2d02-a0fc4bd4ee83.png)

##「Step1基本画面元素設定」
1．Page-Based Appで新しいプロジェクト作成し、Main.storyboardのData View（2番目のBoard）のLabelと白いViewを削除、ModelController.swiftとDataViewController.swiftに関する変数コードも削除
![Screen Shot 0031-03-16 at 8.48.38 PM.png](https://qiita-image-store.s3.amazonaws.com/0/369482/0f24932f-03df-9760-a629-78d9c835fe90.png)
![Screen Shot 0031-03-16 at 9.42.57 PM.png](https://qiita-image-store.s3.amazonaws.com/0/369482/362b79e4-5ae7-c40c-9ebc-4c1d3b1b5c3a.png)

２．Data ViewにNavigation Barを配置して、NavigationItemをNavigation　Barに入れ
![Screen Shot 0031-03-16 at 9.08.24 PM.png](https://qiita-image-store.s3.amazonaws.com/0/369482/6356b518-ceee-7fcc-24b3-a3e67dbe2f2d.png)
3．NavigationItemのStyleを設定（見た目）
![Screen Shot 0031-03-16 at 9.19.36 PM.png](https://qiita-image-store.s3.amazonaws.com/0/369482/03b29937-bdc4-5e06-a000-ecbd910c21dc.png)
４．日、月、火、水、木、金、土のLabelを配置
※一番良いやり方は1個のsectionでDateFormatter.monthSymbolsに代入と思ったんけど、@sakuranさんのコードを参考して、２つのsectionを作ると、section[0]の内容しか出てこない。〜失敗した。原因不明。
５．Data ViewにCollection Viewを配置して、CellにLabel（d）を配置
※カレンダーを作るためには、Cellに1個のLabelが十分、mは別の目的で作ったもので、無視
![Screen Shot 0031-03-16 at 9.05.48 PM.png](https://qiita-image-store.s3.amazonaws.com/0/369482/3b4301db-ab50-29ae-11ae-0f63b35323f4.png)
![Screen Shot 0031-03-16 at 9.14.00 PM.png](https://qiita-image-store.s3.amazonaws.com/0/369482/bf3ee333-2746-4ee9-3541-0c837a352884.png)
６．CellのidentifierをmyCellに設定
![Screen Shot 0031-03-16 at 10.30.13 PM.png](https://qiita-image-store.s3.amazonaws.com/0/369482/ffe1a727-9c02-cc64-706d-5564d47188d4.png)

ここまで、画面は準備完了。
##「Step2」必要なObjectを作成
1.Ctrl ＋マウスドラグでDataViewで関連なObjectをリンク（宣言）
このやり方は説明難いから、わからなければ、Stanfordのvideoを見て勉強してください
![Screen Shot 0031-03-16 at 10.23.08 PM.png](https://qiita-image-store.s3.amazonaws.com/0/369482/e076716d-cd7c-7b83-8e00-1ae558890bb8.png)
２．CellのクラスdayCell.swiftを作成して、Labelをリンク

```swift:dayCell.swift
import UIKit

class dayCell: UICollectionViewCell {
    @IBOutlet weak var dayLabel: UILabel!

    //背景色を白にする
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)!
        self.backgroundColor = UIColor.white
    }
}
```
##「Step3」DataViewController.swiftで１ヶ月分のカレンダーを計算函数を作成

```swift:DataViewController.swift
    var monthSymbol:String = ""
    var year:Int = 2018
    var month:Int = 1
    var days:[String] = []
    var moneys:[Int16:String] = [:]
　　//画面に表示するデータを呼び出しメソッド
    func reloadData(){
　　　　　//year年month月1日でdateComponentsを作る
        let dateComponents = DateComponents(calendar: Calendar.current, timeZone: TimeZone.current, year: year, month: month, day: 1) 
　　　　　//その月の1日の絶対値を取得（僕の簡単の理解。正しいことをGoogleでCalendar関する知識を探してください）
        let firstDay = dateComponents.date! //その月の1日の絶対値
        days = getDays(theFirstDay: firstDay)
  
        let formatter = DateFormatter()
        formatter.dateFormat = DateFormatter.dateFormat(fromTemplate: "GyM", options: 0, locale: .current) //和暦のStyleに設定
        let dateLocale = formatter.string(from: firstDay) //平成31年3月
        navigationBar.topItem?.title = dateLocale
    }
    //何年何月の1ヶ月分のカレンダーの配列を作成函数
    func getDays(theFirstDay:Date) -> [String]{
        var _days = [String]()
        let weeksCount = Calendar.current.range(of: .weekOfMonth, in: .month, for: theFirstDay)!.count  //該日付の月には何週間があること
        let firstWeekday = Calendar.current.component(.weekday, from: theFirstDay)  //該日付の一日は何曜日のこと。日:1,火:2,水:3,木:4,金:5,土:6
        let daysCount = Calendar.current.range(of: .day, in: .month, for: theFirstDay)!.count //該日付の月に何日があること
　　　　　//毎週7日間で、カレンダーを作成、無い日は空白する
        for i in 1...weeksCount*7
        {
            if i < firstWeekday || i > daysCount + firstWeekday - 1
            {
                _days.append("")
            }else
            {
                _days.append(String(describing: i - firstWeekday + 1))
            }
        }
        return _days
    }
```
##「Step4」CollectionView関する函数を設定
```swift:DataViewController.swift
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        reloadData()
        calendarHeight.constant = calendarCollectionView.collectionViewLayout.collectionViewContentSize.height
    }
    
    @IBAction func NextYear(_ sender: UIBarButtonItem) {
        self.year += 1
        reloadData()
        calendarCollectionView.reloadData()
       calendarHeight.constant = calendarCollectionView.collectionViewLayout.collectionViewContentSize.height
    }
    
    @IBAction func LastYear(_ sender: UIBarButtonItem) {
        self.year -= 1
        reloadData()
        calendarCollectionView.reloadData()
       calendarHeight.constant = calendarCollectionView.collectionViewLayout.collectionViewContentSize.height
    }
    
    // MARK: UICollectionViewDelegate
    //set the section number
    func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
        return 1
    }
    
    //cell numbers
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return days.count
    }
 
    //Add cells to collectionView
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let viewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "myCell",for: indexPath) as! dayCell
        let day = days[indexPath.row]
            viewCell.dayLabel.text = day
        return viewCell
    }
    
    //CellSizeの自動調整。Reference to @BMJr 
    func  collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath ) -> CGSize {
        let myBoundWidth: CGFloat = UIScreen.main.bounds.size.width
        let cellSize:CGFloat = myBoundWidth/7.5
        return CGSize(width: cellSize, height: cellSize)
    }
    
    //Section Minimum Space Reference to @BMJr 
    func collectionView(_ collectionView: UICollectionView,layout collectionViewLayout:UICollectionViewLayout,minimumLineSpacingForSectionAt section:Int) -> CGFloat{ return 1}
```
##「Step5」ページング函数の設定
```swift:ModelController.swift
class ModelController: NSObject, UIPageViewControllerDataSource {
    var year:Int = 2019
　　//DataViewのIndex（何番目）を設定する函数
    func viewControllerAtIndex(_ index: Int, storyboard: UIStoryboard) -> DataViewController? {
        // Create a new view controller and pass suitable data.
        let dataViewController = storyboard.instantiateViewController(withIdentifier: "DataViewController") as! DataViewController
        dataViewController.year = self.year
        dataViewController.month = index
        return dataViewController
    }
　　//現在DataViewが所在Index（何番目）を取得する
    func indexOfViewController(_ viewController: DataViewController) -> Int {
        // Return the index of the given data view controller.
        self.year = viewController.year
        return viewController.month
    }

    // MARK: - Page View Controller Data Source
　　//前のページにする函数
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        var index = self.indexOfViewController(viewController as! DataViewController)
        index -= 1
        if (index == 0) || (index == NSNotFound) {
            self.year -= 1
            index = 12
        }
        return self.viewControllerAtIndex(index, storyboard: viewController.storyboard!)
    }
    //後ろのページする函数
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        var index = self.indexOfViewController(viewController as! DataViewController)
        index += 1
        if index > 12 {
            self.year += 1
            index = 1
        }
        return self.viewControllerAtIndex(index, storyboard: viewController.storyboard!)
    }
}
```
##「Step6」初期化のページを設定する
```swift:RootViewController.swift
        let dateComponents = Calendar.current.dateComponents(in: TimeZone.current, from: Date()) //現在の日付を取得
        let initalPageIndex = dateComponents.month ?? 1 //現在の月（数字）をページ順にする
        modelController.year = dateComponents.year ?? 2020  //現在の年に設定する、nilなら2020にする
        let startingViewController: DataViewController = self.modelController.viewControllerAtIndex(initalPageIndex, storyboard: self.storyboard!)!
```
以上！