iOS Calendar Week/Day View in Swift
JZCalendarWeekView
Calendar Week & Day View in iOS Swift.
Features
- [x] X-Day per Page (Day view: 1-day, 3-day view, weekview: 7-day)
- [x] Two Scroll types: One-Day scroll (scroll a section) or Page scroll
- [x] Two Types of Long Press Gestures: Add a new event & Move an existing event
- [x] Events display on calendar view (supports events with conflict time and events crossing few days)
- [x] Support all device orientations (including iPhone X Landscape) and iPad (Slide Over and Split View)
- [x] Current time line displays in today section only
Usage
ViewController
In your viewController, you only need do few things.
- Setup your own custom calendarWeekView in
viewDidLoad
calendarWeekView.setupCalendar(numOfDays: 7,
setDate: Date(),
allEvents: JZWeekViewHelper.getIntraEventsByDate(originalEvents: events),
scrollType: .pageScroll,
firstDayOfWeek: .Monday)
- Override
viewWillTransition
and callviewTransitionHandler
inJZWeekViewHelper
to support all device orientations
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
JZWeekViewHelper.viewTransitionHandler(to: size, weekView: calendarWeekView)
}
- Setup your own custom flowLayout style in
viewDidLoad
(optional)
calendarWeekView.updateFlowLayout(JZWeekViewFlowLayout(hourHeight: 50, rowHeaderWidth: 50, columnHeaderHeight: 50, hourGridDivision: JZHourGridDivision.noneDiv))
JZBaseWeekView
Create your own WeekView class inheriting from JZBaseWeekView
, and you should override the following functions.
- Register function: Register your own
UICollectionReusableView
here. (CollectionViewCell, SupplementaryView or DecorationView)
override func registerViewClasses() {
super.registerViewClasses()
// Register CollectionViewCell
self.collectionView.register(UINib(nibName: "EventCell", bundle: nil), forCellWithReuseIdentifier: "EventCell")
// Register DecorationView: must provide corresponding JZDecorationViewKinds
self.flowLayout.register(BlackGridLine.self, forDecorationViewOfKind: JZDecorationViewKinds.verticalGridline)
self.flowLayout.register(BlackGridLine.self, forDecorationViewOfKind: JZDecorationViewKinds.horizontalGridline)
// Register SupplementrayView: must override collectionView viewForSupplementaryElementOfKind
collectionView.register(RowHeader.self, forSupplementaryViewOfKind: JZSupplementaryViewKinds.rowHeader, withReuseIdentifier: "RowHeader")
}
If you want to use your own supplementryView, you should register it and override the following function
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView
- CollectionView
cellForItemAt
: Use your custom collectionViewCell
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let date = flowLayout.dateForColumnHeader(at: indexPath)
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: EventCell.className, for: indexPath) as! EventCell
cell.updateView(event: allEventsBySection[date]![indexPath.row] as! Event)
return cell
}
JZLongPressView
This view is inheriated from JZBaseWeekView
and implements the long press gestures. You can simply follow the setup rules of JZBaseWeekView
.
In order to achieve the long press gestures, you should implement the JZLongPressViewDelegate
and JZLongPressViewDataSource
in your ViewController.
public protocol JZLongPressViewDelegate: class {
/// When addNew long press gesture ends, this function will be called.
func weekView(_ weekView: JZLongPressWeekView, didEndAddNewLongPressAt startDate: Date)
/// When Move long press gesture ends, this function will be called.
func weekView(_ weekView: JZLongPressWeekView, editingEvent: JZBaseEvent, didEndMoveLongPressAt startDate: Date)
/// Sometimes the longPress will be cancelled because some curtain reason.
func weekView(_ weekView: JZLongPressWeekView, longPressType: JZLongPressWeekView.LongPressType, didCancelLongPressAt startDate: Date)
}
public protocol JZLongPressViewDataSource: class {
/// Implement this function to customise your own AddNew longPressView
func weekView(_ weekView: JZLongPressWeekView, viewForAddNewLongPressAt startDate: Date) -> UIView
/// Implement this function to customise your own Move longPressView
func weekView(_ weekView: JZLongPressWeekView, movingCell: UICollectionViewCell, viewForMoveLongPressAt startDate: Date) -> UIView
}
Also, you should provide the long press types and there are some other properties you can change.
calendarWeekView.longPressDelegate = self
calendarWeekView.longPressDataSource = self
calendarWeekView.longPressTypes = [.addNew, .move]
// Optional
calendarWeekView.addNewDurationMins = 120
calendarWeekView.moveTimeMinInterval = 15
If you want to use the move
type long press, you have to inherit your UICollectionViewCell
from JZLongPressEventCell
to allow retrieving editing JZBaseEvent
because of UICollectionView
reuse problem. Also, remember to set your cell backgroundColor
in cell contentView
.
JZBaseEvent
In JZCalendarWeekView, the data model is using [Date: [Event]]
dictionary because for each day (a section in collectionView), there might be some events.
A static function called getIntraEventsByDate
provided in JZWeekViewHelper
allow you to tranform your events list into [Date: [Event]]
dictionary.
open class func getIntraEventsByDate<T: JZBaseEvent>(originalEvents: [T]) -> [Date: [T]]
In order to call this function, you should create a subclass of JZBaseEvent
and also implement the NSCopying
protocol.
For the intraStartDate
and intraEndDate
in JZBaseEvent
, it means that if a event crosses two days, it should be devided into two events but with different intraStartDate and intraEndDate.
eg. startDate = 180329 14:00, endDate = 180330 03:00, then two events should be generated: 1. 180329 14:00(IntraStart) - 23:59(IntraEnd) 2. 180330 00:00(IntraStart) - 03:00(IntraEnd)
For futher usage, you can also check the example project, some comments in code or just email me.
Requirements
- iOS 9.0+
- Xcode 9.3+
- Swift 4.1+
Installation
Cocoapods
JZCalendarWeekView can be added to your project by adding the following line to your Podfile
:
pod 'JZCalendarWeekView', '~> 0.3'
Todo
- [ ] Support custom decoration/supplementry view added (All-Day events and others)
- [ ] Theme implementation
- [ ] New scroll type: Infinite scroll
- [ ] Support different types of event arrangment rules
Author
Jeff Zhang, zekejeff@gmail.com
If you have any questions and suggestions, feel free to contact me.