iOS Swift 日历周/日视图
灵感来自 WRCalendarView
特性
- 每页 X 天(日视图:1 天,3 天视图,周视图:7 天)
- 两种滚动类型:单日滚动(滚动一个部分)或页面滚动
- 两种长按手势类型:添加新事件和移动现有事件
- 事件在日历视图中显示(支持冲突时间的活动和跨越多天的事件)
- 设置水平可滚动日期范围
- 支持所有设备方向(包括 iPhone X 横屏)和 iPad(滑动和分割视图)
- 自定义当前时间线
- 全天活动
使用方法
ViewController
在您的 ViewController 中,您只需做几件事情。
- 在
viewDidLoad
中设置自己的自定义 calendarWeekView
calendarWeekView.setupCalendar(numOfDays: 7,
setDate: Date(),
allEvents: JZWeekViewHelper.getIntraEventsByDate(originalEvents: events),
scrollType: .pageScroll,
firstDayOfWeek: .Monday)
- 重写
viewWillTransition
并在JZWeekViewHelper
中调用viewTransitionHandler
以支持所有设备方向
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
JZWeekViewHelper.viewTransitionHandler(to: size, weekView: calendarWeekView)
}
- 在
viewDidLoad
中设置自己的自定义 flowLayout 样式(可选)
calendarWeekView.updateFlowLayout(JZWeekViewFlowLayout(hourHeight: 50, rowHeaderWidth: 50, columnHeaderHeight: 50, hourGridDivision: JZHourGridDivision.noneDiv))
JZBaseWeekView
创建自己的继承自 JZBaseWeekView
的 WeekView 类,并应该重写以下函数。
- 注册函数:在此处注册您自己的
UICollectionReusableView
。(CollectionViewCell、SupplementaryView 或 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")
}
如果您想使用您自己的补充视图(包括您当前的时序),您应该注册它并重写以下函数
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView
- CollectionView 的
cellForItemAt
方法:使用您自定义的 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
此视图继承自 JZBaseWeekView
并实现了长按手势。您可以简单地遵循 JZBaseWeekView
的设置规则。
为了实现长按手势,您应在您的 ViewController 中实现 JZLongPressViewDelegate
和 JZLongPressViewDataSource
。
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
}
您还需要提供长按类型,还有其他一些可以更改的属性。
calendarWeekView.longPressDelegate = self
calendarWeekView.longPressDataSource = self
calendarWeekView.longPressTypes = [.addNew, .move]
// Optional
calendarWeekView.addNewDurationMins = 120
calendarWeekView.moveTimeMinInterval = 15
如果您想使用 move
类型的长按,您必须从 JZLongPressEventCell
继承您的 UICollectionViewCell
以允许检索编辑 JZBaseEvent
,因为存在 UICollectionView
重用问题。记得设置您的细胞 backgroundColor
在细胞 contentView
中。
JZBaseEvent
在 JZCalendarWeekView 中,数据模型使用 [Date: [Event]]
字典,因为对于每一天(collectionView中的一个部分),可能会有一些事件。
JZWeekViewHelper
中提供的静态函数 getIntraEventsByDate
允许您将事件列表转换为 [Date: [Event]]
字典。
open class func getIntraEventsByDate<T: JZBaseEvent>(originalEvents: [T]) -> [Date: [T]]
为了调用此函数,您应该创建一个 JZBaseEvent
的子类,并实现 NSCopying
协议。JZBaseEvent
中的 intraStartDate
和 intraEndDate
的含义是,如果一个事件跨越两天,则应将其分割成两个事件,但有不同的 intraStartDate
和 intraEndDate
。
例如,起始日期 = 180329 14:00,结束日期 = 180330 03:00,则应生成两个事件:1. 180329 14:00(内部起始) - 23:59(内部结束) 2. 180330 00:00(内部起始) - 03:00(内部结束)
全天事件
全天功能旨在单独显示全天事件,但只有标记为 isAllDay
为 true 的事件才能显示。对于跨越几天的 evento 建议保持 isAllDay
为 false。(参考 Apple Calendar & Google Calendar)
为了激活全天功能,您只需做两件事。
- 从
JZAllDayEvent
继承您的事件类,以确保添加isAllDay
变量。 - 在您自定义的 CalendarViewWeekView 中,重写
viewForSupplementaryElementOfKind
并使用updateView
在AllDayHeader
中更新您全天视图,使用您自己的视图。示例
水平可滚动范围
水平可滚动范围日期允许您设置您首选的可滚动范围。CalendarWeekView只能从startDate
(包含)横向滚动到endDate
(包含)。nil
表示无限制。
- 您可以在调用
setupCalendar()
时设置scrollableRange
,或者简单更改此变量。 - 如果您在未调用
forceReload()
的情况下更改scrollType
,您应调用setHorizontalEdgesOffsetX()
来重置边缘,因为对于不同的滚动类型,边缘是不同的。
要求
- iOS 9.0+
- Xcode 10+
- Swift 4.2
安装
CocoaPods
JZCalendarWeekView可以通过将以下行添加到您的Podfile
中添加到您的项目中
# Latest release in CocoaPods (recommend to use latest version before v1.0.0 release, optional: provide version number)
pod 'JZCalendarWeekView'
Carthage
JZCalendarWeekView 可以通过在您的 Cartfile
中添加以下行添加到您的项目中:
# Latest release on Carthage (recommend to use latest version before v1.0.0 release, optional: provide version number)
github "zjfjack/JZCalendarWeekView"
Todo
- 用于不同背景视图的装饰视图(参考 #12)
- 日期范围限制:日历视图中的开始时间和结束时间(垂直)
- 主题实现
- 新滚动类型:无限滚动
- 支持不同类型的事件排列规则
作者
Jeff Zhang, [email protected]
如果您有任何问题和建议,请随时联系我。
许可协议
JZCalendarWeekView 在 MIT 许可协议下可用。有关更多信息,请参阅 LICENSE。