LoginSignup
2
5

More than 5 years have passed since last update.

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

Last updated at Posted at 2019-03-16

メイン参考:
@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

「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
Screen Shot 0031-03-16 at 9.42.57 PM.png

2.Data ViewにNavigation Barを配置して、NavigationItemをNavigation Barに入れ
Screen Shot 0031-03-16 at 9.08.24 PM.png
3.NavigationItemのStyleを設定(見た目)
Screen Shot 0031-03-16 at 9.19.36 PM.png
4.日、月、火、水、木、金、土のLabelを配置
※一番良いやり方は1個のsectionでDateFormatter.monthSymbolsに代入と思ったんけど、@sakuranさんのコードを参考して、2つのsectionを作ると、section[0]の内容しか出てこない。〜失敗した。原因不明。
5.Data ViewにCollection Viewを配置して、CellにLabel(d)を配置
※カレンダーを作るためには、Cellに1個のLabelが十分、mは別の目的で作ったもので、無視
Screen Shot 0031-03-16 at 9.05.48 PM.png
Screen Shot 0031-03-16 at 9.14.00 PM.png
6.CellのidentifierをmyCellに設定
Screen Shot 0031-03-16 at 10.30.13 PM.png

ここまで、画面は準備完了。

「Step2」必要なObjectを作成

1.Ctrl +マウスドラグでDataViewで関連なObjectをリンク(宣言)
このやり方は説明難いから、わからなければ、Stanfordのvideoを見て勉強してください
Screen Shot 0031-03-16 at 10.23.08 PM.png
2.CellのクラスdayCell.swiftを作成して、Labelをリンク

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で1ヶ月分のカレンダーを計算函数を作成

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関する函数を設定

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」ページング函数の設定

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」初期化のページを設定する

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!)!

以上!

2
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
5