Skip to content

Common Questions

JTAppleCalendar edited this page Aug 21, 2016 · 51 revisions
  1. How do I disable a Date from being tapped? / How do I make dates invisible?
  2. How do I set the number of rows per month to 4 or 5?
  3. How do I add a section header?
  4. I have some dates from a server, how do I have them selected before my application starts?
  5. Common reloading patterns
  6. Help!! I seem to have some extra space shown above my calendar view.
  7. Is it possible to show two months on the same screen?
  8. How do I implement range selection?
  9. My calendar is lagging on device/ myViews are being randomly repeated across dateCells
  10. How do I test your latest code to see if my bug is fixed there?

1

How do I disable a Date from being tapped? / How do I make dates invisible?

It's pretty much the same as any UIView. You can disable a cell by setting userInteractionEnabled of the CalendarCell to true or false.

userInteractionEnabled = false

So let's say youre in the month of April, and you do not want a user to select the gray colored dates in the previous month of March or the gray colored dates in the future month of May, you can do the following.

// Assuming you're inside the CellView.swift class in the sample app
if cellState.belongsTo = .ThisMonth {
   self.userInteractionEnabled = true
} else {
   self.userInteractionEnabled = false
}

Cells can also be made hidden with the same approach. Just set the view's hidden property to false. The following line of code will only hide dates belonging to the previous month.

if cellState.dateBelongsTo == .PreviousMonthWithinBoundary {
    self.hidden = false
} else {
    self.hidden = true
}
  • .ThisMonth = the date to be displayed belongs to the month section
  • .PreviousMonthWithinBoundary = date belongs to the previous month, and it is within the date boundary you set
  • .PreviousMonthOutsideBoundary = date belongs to previous month, and it is outside the boundary you have set
  • .FollowingMonthWithinBoundary = date belongs to following month, within boundary
  • .FollowingMonthOutsideBoundary = date belongs to following month, outside boundary

2

How do I set the number of rows per month to 4 or 5?

You can't. The calendar displays 1, 2, 3 & 6 rows. Setting it to 4 or 5, forcefully resets it to 6.

And why? Because sometimes a month can take up 6 rows maximum.

  • If you set it to 1, then 6 is divisible by 1. Therefore, there will be 6 single rows to display the month.
  • If you set it to 2, then 6 is divisible by 2. Therefore, there will be 3 double rows to display the month.
  • Setting to 3 means, 2 triple rows displayed to display a month.
  • Setting to six means 1 single 6 row section to display a month.

If you have any suggestions on how this can be improved, let me know by opening an issue. If you really do not want to display the 6 then you can simply hide the 6th row when needed. Hiding is as simple as checking the cellState.

// Assuming youre in the cellView class of the sample app provided on Github.
if cellState.row == 6 {
   self.hidden = true
}

NOTE: there is an updatecoming where you can disable the calendar from generating unnecessary end rows. So lets say your month has 5 rows, it will display 5. But if your month has 6 rows, it will display 6. This update is coming soon, but in the mean time, use the methods shown above, or open an issue and I will try to find a better solution for you.

3

How do I add a section header?

If you are adding section headers you do it as follows:

  1. create a yourCustomHeader.xib file and design it how ever you want. Follow the same steps for creating the custom cell shown in the the Getting Started tutorial. The only difference is that the view should be a subclass of JTAppleHeaderView. All other steps is the same

  2. Register your class just like you did the cell in the tutorial.

calendarView.registerHeaderViewXibs(fileNames: ["PinkSectionHeaderView"])
  1. Finally, If youre registering only one header, then you must implement the following 2 delegate methods:
func calendar(calendar: JTAppleCalendarView, sectionHeaderSizeForDate date: (startDate: NSDate, endDate: NSDate)) -> CGSize 
func calendar(calendar: JTAppleCalendarView, isAboutToDisplaySectionHeader header: JTAppleHeaderView, date: (startDate: NSDate, endDate: NSDate), identifier: String)

If you registered more than one header however, you must implement additional method:

func calendar(calendar: JTAppleCalendarView, sectionHeaderIdentifierForDate date: (startDate: NSDate, endDate: NSDate)) -> String?

4

I have some dates from a server, how do I have them selected before my application starts?

You can have them selected by using the selectDate function.

self.calendarView.selectDates([NSDate()])

Keep in mind that this function triggers the didSelect delegate. Sometimes, you may not want this delegate to be called. In that case you can use the other options of this same function.

self.calendarView.selectDates([NSDate()], triggerSelectionDelegate: false)

Note: If you called a calendarView.reloadData() function, and you want to do a selection right afterward. Then doing it like the following will not work properly:

// Common mistake
calendarView.reloadData()
self.calendarView.selectDates([NSDate()])

This may not work because reloadData() occurs on another thread. Below is the proper way

// Proper way
calendarView.reloadData() {
    self.calendarView.selectDates([NSDate()])
}

5

Common reloading patterns

  1. No scrolling on viewDidload(). We just want to setup our labels with the current date
override func viewDidLoad() {
...
    calendarView.reloadData()
    let currentDate = self.calendarView.currentCalendarDateSegment()
}
  1. We just reloaded the calendarView. We want to scroll to a particular date
override func viewDidLoad() {
...
    calendarView.reloadData()
    // You can do any of the following based on your needs

    //1. This automatically triggers your delegates
    calendarView.scrollToDate(myDate) 

    //2. Self explanatory. 
    calendarView.scrollToDate(myDate, triggerScrollToDateDelegate: false)

    //3. After we reload, we may want to scroll to a date and run some code when scrolling completes.
    //   If code needs to be run after the scrolling, it must be placed in the trailing closure
    calendarView.scrollToDate(myDate, triggerScrollToDateDelegate: false){
        let currentDate = self.calendarView.currentCalendarDateSegment()
    }
}
  1. You can also accomplish the same as above with the following code
calendarView.reloadData(withAnchorDate: myDate){
    let currentDate = self.calendarView.currentCalendarDateSegment()
}

6

Help!! I seem to have some extra space shown above my calendar view.

If this does not solve your problem, then let me know -> https://github.com/patchthecode/JTAppleCalendar/issues/31#issuecomment-222337818

7

Is it possible to show two months on the same screen?

This would mean that you wish to make your date cells smaller. Try using the following property:

let someSmallerDateCellValue = 20
calendarView.itemSize = someSmallerDateCellValue

8

How do I implement range selection?

Although the implementation is up to you, two things are necessary:

  1. calendarView.allowsMultipleSelection = true
  2. calendarView.rangeSelectionWillBeUsed = true

With this, you can now start selecting your ranges however you want with your code. To help you select ranges, the following function is available.

func selectDates(from startDate: myStartDate to endDate: myEndDate)

Final step is to check to see what is the type of selection you have on your cell so that you can know when to display for example a circle styled selection, a left-end styled selection, a right-end styled selection or a middle styled selection.

You can have the following code running in two places.

switch cellState.selectedPosition() {
    case .Full, .Left, .Right:
        selectedView.backgroundColor = UIColor.yellowColor() // Or you can put what ever you like for your rounded corners, and your stand-alone selected cell
    case .Middle:
        selectedView.backgroundColor = UIColor.blueColor() // Or what ever you want for your dates that land in the middle
    default:
        selectedView.backgroundColor = nil // Have no selection when a cell is not selected
}

This code has to be placed in the code path of:

  1. The isAboutToDisplayCell delegate function.
  2. The selectionDidChange code path. This code path includes both didSelect, and didDeselect delegate functions. Because whenever a cell is selected/deselected, the calendar must update the look of the cell.

9

My calendar is lagging on device/ myViews are being randomly repeated across dateCells

Keep in mind that JTAppleCalendar is like a UITableView. The function:

func calendar(calendar: JTAppleCalendarView, isAboutToDisplayCell cell: JTAppleDayCellView, date: NSDate, cellState: CellState)

will be called for every dateCell displayed just like a UITableView cellForRowAtIndexPath function. You are required to setup things in this function fast. Do not put loops in there or other time consuming tasks that you would not put in a UITableView's cellForRowAtIndexPath method. This function should exit fast. This should cure your lagging issue. I have tested this calendar with an old iPhone 4s, and all was well.

To cure your random repeating views -> If you have ever done a UITableView before, then inside the cellForRowAtIndexPath function, you have to reset the cell before it is used right? You will have to remove that circle you have added. Reset the old text you put, change that image you created etc etc. Therefore you have to do the same thing in your isAboutToDisplayCell function.

10

How do I test your latest code to see if my bug is fixed there?

To test the master branch with your current project do this:

Go to your pod file, and change your JTAppleCalendar pod to this:

pod 'JTAppleCalendar', :git => 'https://github.com/patchthecode/JTAppleCalendar.git'

Then do a:

pod install

You can switch back to what you had before once you're done. Nothing on your project will be affected (Unless you actually made changes to the JTAppleCalendar internal library code itself. If you did that, it will be reset)

Clone this wiki locally