iOS

Implement range day calendar picker using JTAppleCalendar

If you’ve ever used JTAppleCalendar to implement day range picker calendar picker. You must have noticed that the way the library implement this feature does not match with common apps we use on the appstore.

If there are values in space between 2 months, the day range selected color band will be repeated if the range has start or end lies between end and start of 2 months. For example, if we select from day 29 of a month to day 1 of the next month using default settings then JTAppleCalendar will display like this:

Day range display with default settings

Not very good, is it? The selected range is duplicated and the empty cells between is not highlighted. What we really want should be:

Day range display as we want

JTAppleCalendar does not support display like the above. Fortunately, with a little trick we can still implement this kind of dispay.

That is when a cell is select we mark the index path for start and end date. So when displaying we’ll check if the index path is between start and end index path, if true then highlight it:

func calculateSelectedPosition(at indexPath: IndexPath,
                               dateBelongsTo: DateOwner,
                               selectedPosition: SelectionRangePosition) -> SelectionRangePosition {
    let isMiddle: Bool

    // All cell betweens selectedStartIndexPath and selectedEndIndexPath will be middle
    if let selectedStartIndexPath = selectedIndexPathRange.value?.start,
       let selectedEndIndexPath = selectedIndexPathRange.value?.end {
        if selectedStartIndexPath < indexPath && indexPath < selectedEndIndexPath {
            isMiddle = true
        } else {
            isMiddle = false
        }
    } else {
        isMiddle = false
    }

    if isMiddle == true {
        return .middle
    } else {
        /*
         If selectedPosition not middle but the date
         does not belong to this month then do not display selectedPostition as none
         */
        if dateBelongsTo != .thisMonth {
            return .none
        } else {
            return selectedPosition
        }
    }
}

That’s all, for more detail check my sample code. Hope this is helpful for you.

Leave a Reply

Your email address will not be published. Required fields are marked *