zjfjack / jzcalendarweekview Goto Github PK
View Code? Open in Web Editor NEWCalendar Week & Day View in iOS Swift
License: MIT License
Calendar Week & Day View in iOS Swift
License: MIT License
Hi, how to have only one event for time slot? Can time conflicts be managed?
tnx for this nice work!
m.
Hey there
I found a strange bug.
The cell widths resize when you scroll in section scroll mode, but only by 1 px on the left side, as if it had something to do with the border or timeline after scrolling.
How to reproduce
With best regards :)
Dark mode theme option like this https://github.com/richardtop/CalendarKit will a great enhancement!
Hello,
Thanks for this really good project!
Is there a way to create programmatically a JZCalendarWeekView?
I'd like to change the height of my calendar week view.
Regards,
Alexandre
Hey there
When you add calendarWeekView.updateWeekView(to: Date())
at the end of LongPressViewController.setupCalendarView()
of your example project like this:
`
calendarWeekView.baseDelegate = self
if viewModel.currentSelectedData != nil {
// For example only
setupCalendarViewWithSelectedData()
} else {
calendarWeekView.setupCalendar(numOfDays: 3,
setDate: Date(),
allEvents: viewModel.eventsByDate,
scrollType: .pageScroll)
}
// LongPress delegate, datasorce and type setup
calendarWeekView.longPressDelegate = self
calendarWeekView.longPressDataSource = self
calendarWeekView.longPressTypes = [.addNew, .move]
// Optional
calendarWeekView.addNewDurationMins = 120
calendarWeekView.moveTimeMinInterval = 15
calendarWeekView.updateWeekView(to: Date())
`
the all-day row disappears. The all-day row appears for a short term when scrolling, but disappears again shortly after. Could there be an update or layouting issue related to updateWeekView(to:)?
I want customise the header of calender like change font colour of toady date and header height.
I've set the numOfDays = 30 so I can display a full month, the problem is that the first day to display is not set, I would like to show only November from 1:st to last. Is it possible?
How can I get the press or click action from the user on one of the cells?
how can we change it to half an hour settings
Hello,
Any suggestions on how to change the background color of a column? Changing the background color of Sundays and Saturdays, for example.
Thanks!
Cool library btw :)
It is limited to days or it can be change to Month view
Hello
First of all thanks for great work! I've been using these library for a month ago and I've seen that calendar locale changes according to the system locale, but I can't find any way to set a fixed locale on week day names. It would be very nice if you could add a locale property to change the calendar language.
Thanks
Good day @zjfjack I am a graphic designer and i want to contribute to your nice project by doing a logo for it. I will be doing it for free as my gift to the project. I need your permission first before I begin my design. Hoping for a positive feedback. Thanks and best regards! - Tobaloidee
Is there any provision so that I want different colour of Hour Grid Divisions
How can I be notified that week/Month has been changed
I am fetching 2 month data from backend services
now I want to be notified when user had switched to third month
Using JZLongPressWeekView
Installed Pods
hi!
tnx for this nice work!
how to make dynamic height for JZAllDayHeader ?
I need to see all the events from allDayevents without scrolling.
Hello, i've been using this library since end of august this year and loving every moment of it. However after updating the library 15 days ago (when 16cf27b ) was merged, i got the following problems which forced me to reverse to the version i had before (whatever version that running 23 nov 2018).
JZLongPressWeekView
that I use as well as the setup method for the calendar in my view controller. I get the same issue even if i change back to using the supplementary views that come with the library!initDateDidChange(_ weekView: JZBaseWeekView, initDate: Date)
does not get called when i scroll to change page.JZLongPressWeekView subclass:
final class WeekCalendarViewModel: JZLongPressWeekView {
private let eventInfoView = CNWeekViewEventInfoView(frame: .zero)
private var eventInfoXConstraint = NSLayoutConstraint()
override func registerViewClasses() {
self.collectionView.register(CNWeekViewCell.self, forCellWithReuseIdentifier: CNCellAndHeaderID.weekCalendarCell)
self.collectionView.registerSupplimentaryViews([CNDateHeader.self, CNMonthHeader.self, JZRowHeader.self, CNAllDayHeader.self])
flowLayout.registerDecorationViews([CNDateHeaderBackground.self, JZRowHeaderBackground.self,
JZAllDayHeaderBackground.self, JZAllDayCorner.self])
flowLayout.register(JZGridLine.self, forDecorationViewOfKind: JZDecorationViewKinds.verticalGridline)
flowLayout.register(JZGridLine.self, forDecorationViewOfKind: JZDecorationViewKinds.horizontalGridline)
collectionView.alwaysBounceVertical = true
collectionView.bounces = true
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CNCellAndHeaderID.weekCalendarCell, for: indexPath) as? CNWeekViewCell else { return UICollectionViewCell() }
cell.configureCell(withEvent: getCurrentEvent(with: indexPath) as? CNWeekViewObject)
return cell
}
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let view: UICollectionReusableView
switch kind {
case CNWeekCalendarSupplementaryViewID.dateHeader:
guard let columnHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: kind, for: indexPath) as? CNDateHeader else { fatalError("CNALlDayHeader failed to be dequeued, WeekCalendarViewModel") }
columnHeader.updateHeaderLabels(date: flowLayout.dateForColumnHeader(at: indexPath))
view = columnHeader
case JZSupplementaryViewKinds.rowHeader:
guard let rowHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: kind, for: indexPath) as? JZRowHeader else { fatalError("CNALlDayHeader failed to be dequeued, WeekCalendarViewModel") }
rowHeader.updateView(date: flowLayout.timeForRowHeader(at: indexPath))
view = rowHeader
case CNWeekCalendarSupplementaryViewID.monthHeader:
guard let cornerHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: kind, for: indexPath) as? CNMonthHeader else { fatalError("CNMonthHeader failed to be dequeued, WeekCalendarViewModel") }
cornerHeader.configureHeader(date: flowLayout.timeForRowHeader(at: indexPath), numOfDays: numOfDays)
view = cornerHeader
case JZSupplementaryViewKinds.currentTimeline:
if currentTimelineType == .page {
guard let currentTimeline = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: kind, for: indexPath) as? JZCurrentTimelinePage else { fatalError("CNALlDayHeader failed to be dequeued, WeekCalendarViewModel") }
view = getPageTypeCurrentTimeline(timeline: currentTimeline, indexPath: indexPath)
} else {
guard let currentTimeline = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: kind, for: indexPath) as? JZCurrentTimelineSection else { fatalError("CNALlDayHeader failed to be dequeued, WeekCalendarViewModel") }
view = getSectionTypeCurrentTimeline(timeline: currentTimeline, indexPath: indexPath)
}
case CNWeekCalendarSupplementaryViewID.allDayHeader:
guard let alldayHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: kind, for: indexPath) as? CNAllDayHeader else { fatalError("CNALlDayHeader failed to be dequeued, WeekCalendarViewModel") }
let date = flowLayout.dateForColumnHeader(at: indexPath)
guard let allDayEvents = allDayEventsBySection[date] as? [CNWeekViewObject] else {
alldayHeader.update(withViews: [])
return alldayHeader
}
alldayHeader.update(withViews: getAllDayHeaderViews(allDayEvents: allDayEvents))
view = alldayHeader
default:
view = UICollectionReusableView()
}
return view
}
private func getAllDayHeaderViews(allDayEvents: [CNWeekViewObject]) -> [UIView] {
var allDayViews = [UIView]()
for event in allDayEvents {
let view = CNWeekViewCell(frame: .zero)
view.configureCell(withEvent: event, isAllDay: event.isAllDay)
allDayViews.append(view)
}
return allDayViews
}
}
extension WeekCalendarViewModel {
// simple logic i implemented to allow the week view to bounce in the bottom, if bounce and alwaysBounceVertical is true.
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.contentOffset.y < 0 {
scrollView.setContentOffset(CGPoint(x: scrollView.contentOffset.x, y: 0), animated: false)
}
}
}
Setup in view controller: where weekCalendar : WeekCalendarViewModel
called in viewDidLoad()
and I perform a forceReload()
with new events in viewWillAppear()
.
weekCalendar.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(weekCalendar)
weekCalendar.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
weekCalendar.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
weekCalendarLeading = weekCalendar.leadingAnchor.constraint(equalTo: view.leadingAnchor)
weekCalendarTrailing = weekCalendar.trailingAnchor.constraint(equalTo: view.trailingAnchor)
weekCalendarLeading.isActive = true
weekCalendarTrailing.isActive = true
weekCalendar.baseDelegate = self
weekCalendar.setupCalendar(numOfDays: 7, setDate: Date(), allEvents: calendarObjectData ?? [Date : [CNWeekViewObject]](), scrollType: .pageScroll, firstDayOfWeek: .Monday, currentTimelineType: .page, visibleTime: Date())
weekCalendar.updateFlowLayout(JZWeekViewFlowLayout(hourGridDivision: JZHourGridDivision.noneDiv))
initDidChange():
func initDateDidChange(_ weekView: JZBaseWeekView, initDate: Date) {
print("initDidChange is called for date: \(initDate)")
loadEventsFromCoreDataContainer(with: initDate)
DispatchQueue.main.async {
self.weekCalendar.forceReload(reloadEvents: self.calendarData)
}
}
Am I alone with this issue and need to debug further? Or did something change in the library that might have introduced this bug? Have I provided enough information?
Thanks for your time!
Thanks for great work!!!
How can I set a custom time duration.
Hi,
Each time I push another view controller after one minute this is crashing
@objc private func minuteTick() {
cachedCurrentTimeComponents.removeAll()
invalidateLayout()
}
the file is JZWeekViewFlowLayout.swift, does need something else? thanks
Hi.
I want to set AllDay Event.
Do you have plan to support this ?
Thanks for great work!
I setup calendar with parameter numOfDays = 1.
calendarWeekView.setupCalendar(numOfDays: 1,
setDate: Date(),
allEvents: viewModel.eventsByDate,
scrollType: .pageScroll)
How can I get the current (selected) date?
func initDateDidChange(_ weekView: JZBaseWeekView, initDate: Date) ?
initDate + numOfDays does not contain the current date.
Hi ,
I am getting "The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions" in JZWeekViewFlowLayout file when run in Xcode 10.2.1.
Hello!
Is there a way to scroll to the first event in a given day? something like scrolltoFirstEvent()?
When showing a great amount of events (screenshot attached), the CalendarView crashes. The last line of the code below crashes with EXC_BAD_INSTRUCTION:
open func getCurrentEvent(with indexPath: IndexPath) -> JZBaseEvent? {
let date = flowLayout.dateForColumnHeader(at: indexPath)
return isAllDaySupported ? notAllDayEventsBySection[date]?[indexPath.row] : allEventsBySection[date]?[indexPath.row]
}
I don't believe it is a good idea to show that many events, therefore a good fix may be to allow a "more events" cell that shows when 3 or 4 events are at the same time.
Another approach may be the solution by Apple, where they overlay certain items, but it also gets very confusing with many events.
Is it possible to specify which hours of the day to display?
I would like to set the beginTime and endTime so I can display a full day 00.00 - 23.59.
(Really great work you have done!)
Hi, thanks for making awesome library ๐
I found a issue on sample app, which sometimes fail to load previous page on 7days and ScrollType Page Scroll.
I recorded movie below.
and my environment is
I checked source code and found in loadPagePageScroll method,
currentOffset is not zero (0.333333333) on 7days and do nothing.
(other days are always 0 and loadPrevPage)
private func loadPagePageScroll() {
let maximumOffset = collectionView.contentSize.width - collectionView.frame.width
// currentOffset sometimes 0.3333333333333333
let currentOffset = collectionView.contentOffset.x
if maximumOffset <= currentOffset {
loadNextOrPrevPage(isNext: true)
}
if currentOffset <= 0 {
loadNextOrPrevPage(isNext: false)
}
}
It works fine with dirty hack changing
currentOffset <= 1
but it looks other original cause currentOffset is not zero on 7days only.
I couldn't find it by myself, and very glad to help or fix this bug ๐
thanks,
I'm not sure if I'm missing something, and I think #11 may be related, but is there an easy way to recognize tap gestures (not long press ones) on events with this library? Could be helpful for a lot of use cases
Hey Jeff
I've found an issue that might be important. Could you have a look at it? Thank you. @zjfjack
These 3 events are from the same day, yet the 3rd appears on the next day:
Here's how to reproduce:
For simplification, use your example code and alter AllDayViewModel like so
class AllDayViewModel: NSObject {
private let firstDate = Date()
private let secondDate = Date().add(component: .minute, value: 22)
private let thirdDate = Date().add(component: .minute, value: 27)
lazy var events = [
AllDayEvent(id: "0", title: "One", startDate: firstDate, endDate: firstDate.add(component: .minute, value: 30), location: "Melbourne", isAllDay: false),
AllDayEvent(id: "1", title: "Two", startDate: secondDate, endDate: secondDate.add(component: .minute, value: 30), location: "Sydney", isAllDay: false),
AllDayEvent(id: "2", title: "Three", startDate: thirdDate, endDate: thirdDate.add(component: .minute, value: 30), location: "Tasmania", isAllDay: false)
]
lazy var eventsByDate = JZWeekViewHelper.getIntraEventsByDate(originalEvents: events)
var currentSelectedData: OptionsSelectedData!
}
It means that 3 events that are very close should be rendered on the same day.
Thank you very much! :)
Hi!
Thank you for sharing your work! I wonder if it is possible to create repeating Events (such as every Monday etc.)? Do you have any suggestions how this could be achieved?
Cheers!
hello,
Is it possible to handle an event All day when I'm tapping on an event which is in frame All day
thanks you
Hi, First of all, thanks for your great repo, I have tried couples of other repos, and all of them were a waste of time till I've found yours.
However, I'm trying to implement a calendar which shows the user four weeks, and it's days so the user can choose which times on which days is he/she free by tapping on cell hours.
The problem is that I don't know where to implement tap gesture.
As you mentioned in #50 in a collectionView subclass inherited from JZBaseWeekView, but In your Example project, I haven't found did you use JZBaseWeekView.
Could you please help me with that?
Appreciate that.
I noticed there is the line print(columnHeaderMinY, collectionView.contentSize.height)
in the JZWeekViewFlowLayout.swift. This seems to be printing a lot as I use the library. Is there any chance you could remove this?
Thanks!
Hello,
First of all, thank you for creating this very useful project.
I'm facing events overlapping due to the wrong cell width calculation.
Check below screenshot, the event's width should scale up to the next event.
Check below screenshot for overlapping event.
I tried to find the cause in the flowlayout file. The issue is due to width calculation logic. Currently, it is calculating width by finding all events that intersect new event and then divide the width by the count of overlapping events. which will work great only until all the events have the same duration.
I have set my available long press types to only .addNew
, but when I long press on a cell as a move it still tries to perform the move long press, and as such the app is crashing. I can see that you check whether the long press types contain .addNew
, but I don't see .move
checked anywhere.
Should be fixed by #21
Hello!
I've been trying to localize the date in JZRowHeader, but I can't figure out how to change setupBasic(). The issue I'm having is that in my method
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
I have to call
if kind == JZRowHeader.className {
let rowHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: kind, for: indexPath) as! JZRowHeader
rowHeader.updateView(date: flowLayout.timeForRowHeader(at: indexPath))
rowHeader.dateFormatter.dateFormat = "h a"
return rowHeader
}
to override the dateformat
However, sometimes the rowHeader still displays the old date format of "HH:mm", even though I set it here. I also can't dequeue the supplementary view as any kind of inherited class, or the app crashes. Is there a suggested way to change the date in this locale?
Hello,
We want to make a shadow in selected cell on long-pressing in week/day view in add new mode but cannot see where and how to do this. This shadow must apply before trigger the long press event to indicate the user the hour that is selecting
Thanks.
Hello!
First of all, thank you for the excellent work on this. One question I do have: I'm trying to add english locale support to show events in am/pm format on the longpress view and in the JZRowHeader. I can get the JZRowHeader to work by changing the dateformatter when overriding viewForSupplementaryElementOfKind
in a subclass of JZLongPressWeekView
. However, I can't change the date format that shows up when you long press an event. I think it's the getTimeIgnoreSecondsFormat
method that is called. Is there any simple way to add am/pm support here? Or can we make some of the private
methods fileprivate
so I can edit the behavior of the long press in a subclass?
Thanks!
Hi,
Thanks for the nice framework.
I want to add action to the week view whether event is available or not.
If there is no event on that particular date and time I want to create an event and event is there then I need to show event details.
Please help me to solve this.
Regards,
Suvarna Ratna A
Hello,
First, VERY GOOD JOB BRO!
I need to localize this String but cannot see how to access lblTitle of JZAllDayCorner from my project.
Thanks
Hello,
Thanks for this great calendar ! You did a great jobs.
I've only one issue, with last iOS SDK and only on new iPad 11 inch with 7 days in Horizontal (I test only on simulator).
You try to scroll to next week, it's ok. But when you trying to do it a second time, it makes a previous move instead of a next.
Very strange, thanks !
Hey there
Another rather important feature request. :)
Right now the calendar seems to be endless, going back and forth "almost" infinite.
Now, imagine a scenario in which the user is not allowed to see past dates. He can only see today and the future. This appears to be rather difficult to implement yet, though I found a workaround (by overriding the scrolling, but it jerky and difficult to use).
It would be much better if we could set the "firstDate" and "endDate" (as if for a time range, i.e. 16 Nov 2018 - 16 Nov 2019) of the calendar, so that the CollectionView bounces the user naturally at the edges of the CollectionView.
With best regards
How show multiple event horizontally
Hello, Thanks for great work!
I'm developing an App where I want to add new event for specific amount of time but this time will not be fixed!! I want to add one event for 1 hour and another one for 4 hours and each event may have different time. so this is my question that how can I achieve this? Like when I long press on time it should start adding event until I scroll down and where I finish long press that selected time should get new event!
Hope you got my point!!
Thank you in Advance!!
I am going to display a week in landscape orientation and a day in portrait. So I change layout to show 7 days and display header by adjusting its height. Before displaying a week I already have some items it data source so I resetup the component and while updating flow layout get fatal error because forceReload
is dispatched async and could not be happened before layout update. In this case while preparing layout collection view still has some items while there are not any items set up.
Here is the code for setting up
private func setupCalendarViewForDisplayingRange(_ range: DisplayingRange) {
guard let calendarWeekView = calendarWeekView else { return }
switch range {
case .day:
calendarWeekView.setupCalendar(numOfDays: 1,
setDate: selectedDate,
allEvents: [:],
scrollType: .sectionScroll,
firstDayOfWeek: .Monday)
calendarWeekView.forceReload(reloadEvents: [:])
calendarWeekView.updateWeekView(to: selectedDate)
let layout = JZWeekViewFlowLayout(hourHeight: nil, rowHeaderWidth: nil, columnHeaderHeight: 0, hourGridDivision: nil)
calendarWeekView.updateFlowLayout(layout)
case .week:
calendarWeekView.setupCalendar(numOfDays: 7,
setDate: selectedDate,
allEvents: [:],
scrollType: .pageScroll,
firstDayOfWeek: .Monday)
calendarWeekView.forceReload(reloadEvents: [:])
calendarWeekView.updateWeekView(to: selectedDate)
let layout = JZWeekViewFlowLayout(hourHeight: nil, rowHeaderWidth: nil, columnHeaderHeight: 50, hourGridDivision: nil)
calendarWeekView.updateFlowLayout(layout)
}
}
Hello,
I faced to a possible date offset bug in one hour, if i long press to create event between 1:00 and 2:00 the start date was 0:00 and end date 1:00 and so on. Only first hour (0:00 to 1:00) was fine.
I have achieved a solution removing this offset (note the stroked part):
let adjustedY = yCollectionView - flowLayout.columnHeaderHeight - flowLayout.contentsMargin.top - flowLayout.allDayHeaderHeight
Probably this issue is caused because i have customised views, but modifying longPressTopMarginY didn't work as expected.
You can close this issue.
Thanks!
I set number of date = 7 in setupCalendar and app crash with error
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
only happen with number of date = 7, code set here
calendarWeekView.setupCalendar(numOfDays: 7,
setDate: Date(),
allEvents: viewModel.eventsByDate,
scrollType: .pageScroll)
open func updateAllDayBar(isScrolling: Bool) {
guard isAllDaySupported else { return } // << crash here
var maxEventsCount: Int = 0
getDatesInCurrentPage(isScrolling: isScrolling).forEach {
let count = allDayEventsBySection[$0]?.count ?? 0
if count > maxEventsCount {
maxEventsCount = count
}
}
flowLayout.allDayHeaderHeight = flowLayout.defaultAllDayOneLineHeight * CGFloat(min(maxEventsCount, 2))
}
Hey there
So far, from what I know, it is relatively difficult to scroll to "today".
Think of the iOS Calendar and its "Today" button.
In order to achieve this, what I do is to setupCalendar(...) once again. That resets the calendar to the requested date. But this is ugly and happens instantly.
It would be better if we could scroll to a specific date. Is that possible already? Am I missing something? Or could you add it? Much appreciated.
With best regards
Hi
I am using ZHourGridDivision.minutes_30 division and i want add row header label for 30 mins also . Like 19:00 , 19:30 etc
thanks
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.