JTAppleCalendar: Strange behaviour on range selection [Bug version 6]

Hi there, I really want to thank you for this awesome library. I implemented a calendar view with one single range selection at a time and everything is working fine. Unfortunately I’m facing a very strange behaviour on dates near to outdate cells. I need to hide outdates cell and I’m using JTAppleCalendar 6.1.6 in order to set minimum deployment target to 8.0. Here a little video of my problem:

ezgif-3-eb85b97f52

//
//  ViewController.swift
//  CalendarTutorial
//

import UIKit
import JTAppleCalendar

class ViewController: UIViewController, JTAppleCalendarViewDataSource, JTAppleCalendarViewDelegate {

    @IBOutlet weak var calendarView: JTAppleCalendarView!
    @IBOutlet weak var headerView: UIView!
    
    let monthFormatter = DateFormatter()
    var currentCalendar = Calendar.current
    
    var checkIn: Date? = nil
    var checkOut: Date? = nil
    var isRangeSelected = false
    
    let colorBelongsTo = UIColor(hex: "2C3135")
    let colorNotBelongTo = UIColor(hex: "B0B0B0")
    let colorSelected = UIColor.white

    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.navigationItem.setSimpleTitle(string: "SELECT DATES")
        
        headerView.backgroundColor = UIColor.init(colorLiteralRed: 43/255.0, green: 48/255.0, blue: 60/255.0, alpha: 1/1.0)
        
        calendarView.dataSource = self
        calendarView.delegate = self
        calendarView.scrollDirection = .vertical
        calendarView.scrollingMode = .none
        calendarView.allowsMultipleSelection = true
        calendarView.rangeSelectionWillBeUsed = true
        calendarView.registerCellViewXib(file: "CellView")
        calendarView.registerHeaderView(xibFileNames: ["CalendarHeaderView"])
        calendarView.cellInset = CGPoint(x: 0, y: 0)
        
        let screenWidth = self.view.frame.size.width
        let itemSize = Double(screenWidth) / 6.5
        calendarView.itemSize = CGFloat(itemSize)
                
        monthFormatter.dateFormat = "MMMM yyyy"
    }
    
    func configureCalendar(_ calendar: JTAppleCalendarView) -> ConfigurationParameters {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy MM dd"
        let startDate = formatter.date(from: "2017 05 24")!
        let endDate = formatter.date(from: "2019 05 24")!
    
        let parameters = ConfigurationParameters(startDate: startDate,
                                                 endDate: endDate,
                                                 numberOfRows: 6,
                                                 calendar: currentCalendar,
                                                 generateInDates: .forAllMonths,
                                                 generateOutDates: .off,
                                                 firstDayOfWeek: .monday)
        return parameters
    }
        
    func calendar(_ calendar: JTAppleCalendarView, willDisplayCell cell: JTAppleDayCellView, date: Date, cellState: CellState) {
        let myCustomCell = cell as! CellView
        
        myCustomCell.dayLabel.text = cellState.text
        
        handleCellTextColor(view: cell, cellState: cellState, state: cellState.dateBelongsTo != .thisMonth)
        handleCellSelection(view: cell, cellState: cellState, state: cellState.dateBelongsTo != .thisMonth)
    }
    
    func calendar(_ calendar: JTAppleCalendarView, sectionHeaderSizeFor range: (start: Date, end: Date), belongingTo month: Int) -> CGSize {
        return CGSize(width: self.view.frame.size.width, height: 92)
    }

    func calendar(_ calendar: JTAppleCalendarView, willDisplaySectionHeader header: JTAppleHeaderView, range: (start: Date, end: Date), identifier: String) {
        let headerCell = (header as? CalendarHeaderView)
        headerCell?.title.text = monthFormatter.string(from: range.start).capitalized
    }
    
    func calendar(_ calendar: JTAppleCalendarView, didSelectDate date: Date, cell: JTAppleDayCellView?, cellState: CellState) {
        if isRangeSelected {
            calendarView.deselectDates(from: checkIn!, to: checkOut!, triggerSelectionDelegate: false)
            checkIn = date
            checkOut = nil
            isRangeSelected = false
            calendarView.selectDates([checkIn!], triggerSelectionDelegate: false, keepSelectionIfMultiSelectionAllowed: true)
        } else {
            if checkIn == nil {
                checkIn = date
                calendarView.selectDates([checkIn!], triggerSelectionDelegate: false, keepSelectionIfMultiSelectionAllowed: true)
            } else {
                if date < checkIn! {
                    calendarView.deselectDates(from: checkIn!, to: checkIn!, triggerSelectionDelegate: false)
                    checkIn = date
                    checkOut = nil
                    isRangeSelected = false
                    calendarView.selectDates([checkIn!], triggerSelectionDelegate: false, keepSelectionIfMultiSelectionAllowed: true)
                } else {
                    checkOut = date
                    isRangeSelected = true
                    calendarView.selectDates(from: checkIn!, to: checkOut!,  triggerSelectionDelegate: false, keepSelectionIfMultiSelectionAllowed: true)
                }
            }
        }
    }
    
    func calendar(_ calendar: JTAppleCalendarView, didDeselectDate date: Date, cell: JTAppleDayCellView?, cellState: CellState) {
        calendarView.deselectAllDates(triggerSelectionDelegate: false)
        if !isRangeSelected {
            checkIn = date
        } else {
            checkIn = date
            checkOut = nil
            isRangeSelected = false
        }
        calendarView.selectDates([checkIn!], triggerSelectionDelegate: false, keepSelectionIfMultiSelectionAllowed: true)
    }
    
    func handleCellTextColor(view: JTAppleDayCellView?, cellState: CellState, state: Bool) {
        guard let myCustomCell = view as? CellView  else {
            return
        }
        
        if cellState.isSelected {
            if cellState.date == checkIn || cellState.date == checkOut {
                myCustomCell.dayLabel.textColor = colorSelected
            } else if cellState.date > checkIn! && cellState.date < checkOut! {
                myCustomCell.dayLabel.textColor = colorBelongsTo
            }
        } else {
            if cellState.dateBelongsTo == .thisMonth {
                myCustomCell.dayLabel.textColor = colorBelongsTo
            } else {
                myCustomCell.dayLabel.textColor = colorNotBelongTo
            }
        }
        
        myCustomCell.isHidden = state
    }
    
    func handleCellSelection(view: JTAppleDayCellView?, cellState: CellState, state: Bool) {
        guard let myCustomCell = view as? CellView  else {
            return
        }
        
        if cellState.isSelected {
            if cellState.date == checkIn {
                if checkOut == nil {
                    myCustomCell.selectedView.image = UIImage(named: "SingleSelection")
                } else {
                    myCustomCell.selectedView.image = UIImage(named: "LeftSelection")
                }
            } else if cellState.date == checkOut {
                myCustomCell.selectedView.image = UIImage(named: "RightSelection")
            } else if cellState.date > checkIn! && cellState.date < checkOut! {
                myCustomCell.selectedView.image = UIImage(named: "ShapeSelection")
            }
        } else {
            myCustomCell.selectedView.image = UIImage()
        }
        
        myCustomCell.isHidden = state
    }
}

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 15 (9 by maintainers)

Commits related to this issue

Most upvoted comments

I’m very happy I helped you to find a bug in your previous version of this awesome control. Thank you @patchthecode. I would like to ask you if you should plan to support iOS 8 for latest release of JTAppleCalendar.