From b9efa01f7ac5ae56bc0bdd72b3eeb1b618dbb00e Mon Sep 17 00:00:00 2001 From: Ehab Abdou Date: Wed, 18 Nov 2015 20:58:59 -0500 Subject: [PATCH] ADDED: Support for multiple date selections. --- Calendar/CalendarKit/CalendarView.swift | 54 +++++++++++++++---- .../CalendarKit/MonthCollectionCell.swift | 15 ++++-- Calendar/CalendarKit/NSDateAdditions.swift | 4 ++ Calendar/ViewController.swift | 17 ++++++ 4 files changed, 76 insertions(+), 14 deletions(-) diff --git a/Calendar/CalendarKit/CalendarView.swift b/Calendar/CalendarKit/CalendarView.swift index 5d57d06..c3ff98e 100644 --- a/Calendar/CalendarKit/CalendarView.swift +++ b/Calendar/CalendarKit/CalendarView.swift @@ -11,8 +11,9 @@ import UIKit // 12 months - base date - 12 months let kMonthRange = 12 -protocol CalendarViewDelegate: class { +@objc protocol CalendarViewDelegate: class { func didSelectDate(date: NSDate) + optional func didChangeSelectedDates(selectedDates: [NSDate]) } class CalendarView: UIView, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, UIScrollViewDelegate, MonthCollectionCellDelegate { @@ -47,17 +48,20 @@ class CalendarView: UIView, UICollectionViewDataSource, UICollectionViewDelegate } } - var selectedDate: NSDate? { + var selectedDates: [NSDate] = [NSDate]() { didSet { collectionView.reloadData() dispatch_async(dispatch_get_main_queue()){ self.moveToSelectedDate(false) - if self.delegate != nil { - self.delegate!.didSelectDate(self.selectedDate!) + if self.delegate != nil && self.selectedDates.count > 0 { + self.delegate!.didSelectDate(self.selectedDates.last!) + self.delegate!.didChangeSelectedDates?(self.selectedDates) } } } } + + var allowMultipleSelections = false override func awakeFromNib() { let nib = UINib(nibName: "MonthCollectionCell", bundle: nil) @@ -65,12 +69,22 @@ class CalendarView: UIView, UICollectionViewDataSource, UICollectionViewDelegate } class func instance(baseDate: NSDate, selectedDate: NSDate) -> CalendarView { + return instance(baseDate, selectedDates: [selectedDate]) + } + + class func instance(baseDate: NSDate, selectedDates: [NSDate]) -> CalendarView { let calendarView = NSBundle.mainBundle().loadNibNamed("CalendarView", owner: nil, options: nil).first as! CalendarView - calendarView.selectedDate = selectedDate + selectedDates.forEach({ (date) -> () in + calendarView.selectedDates.append(date.startOfDay) + }) + if calendarView.selectedDates.count == 0 { + calendarView.selectedDates.append(NSDate().startOfDay) + } calendarView.baseDate = baseDate return calendarView } + func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return collectionData.count } @@ -82,8 +96,11 @@ class CalendarView: UIView, UICollectionViewDataSource, UICollectionViewDelegate cell.monthCellDelgate = self cell.logic = collectionData[indexPath.item] - if cell.logic!.isVisible(selectedDate!) { - cell.selectedDate = Date(date: selectedDate!) + cell.selectedDates.removeAll() + for date in selectedDates { + if cell.logic!.isVisible(date) { + cell.selectedDates.append(Date(date: date)) + } } return cell @@ -140,7 +157,7 @@ class CalendarView: UIView, UICollectionViewDataSource, UICollectionViewDelegate var index = -1 for var i = 0; i < collectionData.count; i++ { let logic = collectionData[i] - if logic.containsDate(selectedDate!) { + if selectedDates.count > 0 && logic.containsDate(selectedDates.last!) { index = i break } @@ -155,6 +172,25 @@ class CalendarView: UIView, UICollectionViewDataSource, UICollectionViewDelegate //MARK: Month cell delegate. func didSelect(date: Date) { - selectedDate = date.nsdate + if !allowMultipleSelections { + selectedDates[0] = date.nsdate.startOfDay + } + else { + selectedDates.append(date.nsdate.startOfDay) + } + } + + func didDeselect(date: Date) { + if selectedDates.count == 1 { + return + } + + for aDate in selectedDates { + if aDate.isSameDay(date.nsdate.startOfDay) { + if let index = selectedDates.indexOf(aDate) { + selectedDates.removeAtIndex(index) + } + } + } } } diff --git a/Calendar/CalendarKit/MonthCollectionCell.swift b/Calendar/CalendarKit/MonthCollectionCell.swift index 838e587..8408079 100644 --- a/Calendar/CalendarKit/MonthCollectionCell.swift +++ b/Calendar/CalendarKit/MonthCollectionCell.swift @@ -10,6 +10,7 @@ import UIKit protocol MonthCollectionCellDelegate: class { func didSelect(date: Date) + func didDeselect(date: Date) } class MonthCollectionCell: UICollectionViewCell, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { @@ -31,7 +32,7 @@ class MonthCollectionCell: UICollectionViewCell, UICollectionViewDataSource, UIC } } - var selectedDate: Date? { + var selectedDates: [Date] = [Date]() { didSet { if collectionView != nil { collectionView.reloadData() @@ -78,8 +79,7 @@ class MonthCollectionCell: UICollectionViewCell, UICollectionViewDataSource, UIC let date = dates[indexPath.item] cell.date = (indexPath.item < dates.count) ? date : nil - cell.mark = (selectedDate == date) - + cell.mark = selectedDates.contains(date) cell.disabled = (indexPath.item < previousMonthVisibleDatesCount) || (indexPath.item >= previousMonthVisibleDatesCount + currentMonthVisibleDatesCount) @@ -89,10 +89,15 @@ class MonthCollectionCell: UICollectionViewCell, UICollectionViewDataSource, UIC func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) { if monthCellDelgate != nil { - monthCellDelgate!.didSelect(dates[indexPath.item]) + if selectedDates.contains(dates[indexPath.item]) { + monthCellDelgate!.didDeselect(dates[indexPath.item]) + } + else { + monthCellDelgate!.didSelect(dates[indexPath.item]) + } } } - + func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView { return collectionView.dequeueReusableSupplementaryViewOfKind(UICollectionElementKindSectionHeader, withReuseIdentifier: "WeekHeaderView", forIndexPath: indexPath) } diff --git a/Calendar/CalendarKit/NSDateAdditions.swift b/Calendar/CalendarKit/NSDateAdditions.swift index bf3dfea..4f8297b 100644 --- a/Calendar/CalendarKit/NSDateAdditions.swift +++ b/Calendar/CalendarKit/NSDateAdditions.swift @@ -91,6 +91,10 @@ extension NSDate { var hour: Int { return components.hour } + + func isSameDay(date: NSDate) -> Bool { + return !(self.year != date.year || self.month != date.month || self.day != date.day) + } //MARK: Private variable and methods. diff --git a/Calendar/ViewController.swift b/Calendar/ViewController.swift index e7e9c34..5a3e9c0 100644 --- a/Calendar/ViewController.swift +++ b/Calendar/ViewController.swift @@ -24,6 +24,9 @@ class ViewController: UIViewController, CalendarViewDelegate { let calendarView = CalendarView.instance(date, selectedDate: date) calendarView.delegate = self calendarView.translatesAutoresizingMaskIntoConstraints = false + +// calendarView.allowMultipleSelections = true //Allows selection of multiple dates. Defaults to false + placeholderView.addSubview(calendarView) // Constraints for calendar view - Fill the parent view. @@ -31,8 +34,22 @@ class ViewController: UIViewController, CalendarViewDelegate { placeholderView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[calendarView]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["calendarView": calendarView])) } + //REQUIRED: Will be called whether allowMultipleSelections is true or false. + //Also will be called in cases of selection and deselection. + // Will return the last SELECTED date available func didSelectDate(date: NSDate) { print("\(date.year)-\(date.month)-\(date.day)") } + + //OPTIONAL: Will return all selected dates. Useful when allowMultipleSelections is true + /* + func didChangeSelectedDates(selectedDates: [NSDate]) { + print("Selected Dates: {") + selectedDates.forEach { (date) -> () in + print("\(date.year)-\(date.month)-\(date.day)") + } + print("}") + } + */ }