LoginSignup
6

More than 3 years have passed since last update.

FSCalendarのカレンダーに点マークを表示する

Last updated at Posted at 2020-09-08

はじめに

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

概要

FSCalendarではカレンダーの日付の下に任意の条件で点マークを表示することができます。
制作したアプリの用途に絡めると「ToDoの登録がある日付に点マークを表示」になります。

今回はRealmSwiftを組み合わせての実装になりますのでRealmSwiftに関しましてはこちら参照ください。
また、FSCalendarの導入に関しましてはこちらを参照ください。

実行環境

【Xcode】 Version 11.7
【Swift】 version 5.2.4
【CocoaPods】version 1.9.3
【RealmSwift】 version 5.3.2
【FSCalendar】version 2.8.1

実装コード

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

Todo.swift
import Foundation
import RealmSwift

class Todo: Object {
    # ・・・省略・・・
    @objc dynamic var dateString: String!
    # ・・・省略・・・
}
MainViewController.swift
import UIKit
import FSCalendar
import CalculateCalendarLogic
import RealmSwift

class MainViewController: UIViewController {

    @IBOutlet weak var calendar: FSCalendar!
    # ・・・省略・・・
    var datesWithEvents: Set<String> = []
    # ・・・省略・・・

    override func viewDidLoad() {
        super.viewDidLoad()
        # ・・・省略・・・
    }
}

extension MainViewController: FSCalendarDelegate, FSCalendarDataSource, FSCalendarDelegateAppearance {
    // 任意の日付に点マークをつける
    func calendar(_ calendar: FSCalendar, numberOfEventsFor date: Date) -> Int{

        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy/MM/dd"
        formatter.calendar = Calendar(identifier: .gregorian)
        formatter.timeZone = TimeZone.current
        formatter.locale = Locale.current
        let calendarDay = formatter.string(from: date)

        // Realmオブジェクトの生成
        let realm = try! Realm()
        // 参照(全データを取得)
        let todos = realm.objects(Todo.self)

        if todos.count > 0 {
            for i in 0..<todos.count {
                if i == 0 {
                    datesWithEvents = [todos[i].dateString]
                } else {
                    datesWithEvents.insert(todos[i].dateString)
                }
            }
        } else {
            datesWithEvents = []
        }
        return datesWithEvents.contains(calendarDay) ? 1 : 0 
    }
}

実装方法

以下のメソッドを用いることで点マークがつけられるようになります。

func calendar(_ calendar: FSCalendar, numberOfEventsFor date: Date) -> Int{
    return 1 //ここに入る数字によって点の数が変わる
}

画面に表示されている月の日付(Date型)がループで投げられます。自動的にFor-in構文のようにdateの数だけこのメソッドが呼ばれるイメージです。
しかしこのまま用いても全ての日付の下に点マークが付くようになるだけになります。
これをRealmSwiftと組み合わせることで、ToDoの登録がある日付にだけ点マークを表示するようにしました。

1.上記メソッドで呼ばれる日付(Date型)と照合させるためのデータ(dateString)を用意し、RealmSwiftに登録

  • RealmSwiftに登録するTodoクラスに下記変数を用意します。
@objc dynamic var dateString: String!
  • Realm Studioで確認すると赤枠の箇所になります。
    スクリーンショット 2020-09-08 22.17.10.png

  • また、メソッドで呼ばれる日付(Date型)をRealmSwiftに保存したデータと同じフォーマットに変換します。

formatter.dateFormat = "yyyy/MM/dd"
let calendarDay = formatter.string(from: date)

2.RealmSwiftからデータを取得

// Realmオブジェクトの生成
let realm = try! Realm()
// 参照(全データを取得)
let todos = realm.objects(Todo.self)

3.取得したデータの中から必要なデータ(dateString)をピックアップして変数に格納

  • RealmSwiftに登録データがある場合は、変数「datesWithEvents」に「dateString」の内容を格納。登録データがない場合は、変数「datesWithEvents」には何も入れません。
if todos.count > 0 {
    for i in 0..<todos.count {
        if i == 0 {
            datesWithEvents = [todos[i].dateString]
        } else {
            datesWithEvents.insert(todos[i].dateString)
        }
    }
} else {
    datesWithEvents = []
}
  • 変数「datesWithEvents」は配列のSetクラス(集合型)になります。Arrayクラスと異なる箇所としましてはインデックス番号が存在せず、重複が許されない型ということ違いがあります。今回RealmSwiftから取得するデータが重複する必要がなかったためSetクラス(集合型)にしております。詳細はこちら参照ください。
var datesWithEvents: Set<String> = []

4.日付と照合させ、Int型を返す

  • 三項演算子を用いて、任意の文字列(calendarDay)が含まれているか判断し、含まれている場合は「1」を、含まれていない場合は「0」を返します。
  • 三項演算子の気をつける点としまして、半角スペースを置かずに「?」をつけると「オプショナル型の宣言」と解釈されエラーになりますのでご注意下さい。
return datesWithEvents.contains(calendarDay) ? 1 : 0 

5.実装後の画面

スクリーンショット 2020-09-08 23.33.18.png

参考

おわりに

自作アプリを制作している際にFSCalendarについての記事はいくつかあり、重宝させて頂きましたが、カレンダーに点マークを表示させるメソッドの紹介記事等で終わっているものが多く、実装に絡めた記事が少なかったので初学者の私からするとイメージがつきにくいなと感じておりました。コードの簡略化等を踏まえると未熟な内容になってしまいますが、誰かのお力になれれば幸いです。

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
6