Now i have the code working properly for the range selection but for the range selection i need only the start and end dates were highlighted with background colour , in between dates should be shaded something like layer , so i need to use the FSCalanderCell for that , i don't know how to implement that prepared cell to this controller based on my need could anyone help out of me from this task
class CalanderViewController : UIViewController {
private weak var calanderView: FSCalendar!
private var datesRange: [Date]?
private var firstDate: Date?
private var lastDate: Date?
init() {
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
setupNavigationBar()
setupViews()
setupConstraints()
}
private func setupNavigationBar() {
self.navigationItem.title = "Calendar"
navigationController?.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.black, .font: FontFamily.Poppins.bold.font(size: 15)!]
navigationItem.backBarButtonItem = UIBarButtonItem(title: "",style: .plain,target: nil,action: nil)
}
private func setupViews() {
let calanderView = FSCalendar()
calanderView.translatesAutoresizingMaskIntoConstraints = false
calanderView.dataSource = self
calanderView.delegate = self
calanderView.scrollDirection = .vertical
calanderView.placeholderType = .none
calanderView.allowsMultipleSelection = true
calanderView.weekdayHeight = 20
calanderView.today = nil
calanderView.calendarHeaderView.isHidden = false
calanderView.register(RangePickerCell.self, forCellReuseIdentifier: "cell")
let appearance = calanderView.appearance
appearance.titleDefaultColor = .black
appearance.calendar.rowHeight = 0
appearance.titleFont = FontFamily.OpenSans.semibold.font(size: 11)
view.addSubview(calanderView)
self.calanderView = calanderView
}
private func setupConstraints() {
NSLayoutConstraint.activate([
self.calanderView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
self.calanderView.leftAnchor.constraint(equalTo: view.leftAnchor , constant: 20),
self.calanderView.rightAnchor.constraint(equalTo: view.rightAnchor , constant: -20),
self.calanderView.heightAnchor.constraint(equalToConstant: 300)
])
}
func datesRange(from: Date, to: Date) -> [Date] {
if from > to { return [Date]() }
var tempDate = from
var array = [tempDate]
while tempDate < to {
tempDate = Calendar.current.date(byAdding: .day, value: 1, to: tempDate)!
array.append(tempDate)
}
return array
}
}
extension CalanderViewController: FSCalendarDataSource , FSCalendarDelegate {
func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
// nothing selected:
if firstDate == nil {
firstDate = date
datesRange = [firstDate!]
print("datesRange contains: \(datesRange!)")
return
}
// only first date is selected:
if firstDate != nil && lastDate == nil {
// handle the case of if the last date is less than the first date:
if date <= firstDate! {
calendar.deselect(firstDate!)
firstDate = date
datesRange = [firstDate!]
print("datesRange contains: \(datesRange!)")
return
}
let range = datesRange(from: firstDate!, to: date)
lastDate = range.last
for d in range {
calendar.select(d)
}
datesRange = range
print("datesRange contains: \(datesRange!)")
return
}
// both are selected:
if firstDate != nil && lastDate != nil {
for d in calendar.selectedDates {
calendar.deselect(d)
}
lastDate = nil
firstDate = nil
datesRange = []
print("datesRange contains: \(datesRange!)")
}
}
func calendar(_ calendar: FSCalendar, didDeselect date: Date, at monthPosition: FSCalendarMonthPosition) {
// both are selected:
if firstDate != nil && lastDate != nil {
for d in calendar.selectedDates {
calendar.deselect(d)
}
lastDate = nil
firstDate = nil
datesRange = []
print("datesRange contains: \(datesRange!)")
}
}
}
//Cell ========>
enum SelectionType {
case none
case today
case single
case leftBorder
case middle
case rightBorder
}
class RangePickerCell: FSCalendarCell {
public weak var circleImageView: UIImageView!
public weak var selectionLayer: CAShapeLayer!
public weak var roundedLayer: CAShapeLayer!
public weak var todayLayer: CAShapeLayer!
var selectionType: SelectionType = .none {
didSet {
setNeedsLayout()
}
}
required init!(coder aDecoder: NSCoder!) {
super.init(coder: aDecoder)
commonInit()
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
private func commonInit() {
let selectionLayer = CAShapeLayer()
selectionLayer.fillColor = UIColor.lightGray.cgColor
selectionLayer.actions = ["hidden": NSNull()]
self.contentView.layer.insertSublayer(selectionLayer, below: self.titleLabel?.layer)
self.selectionLayer = selectionLayer
let roundedLayer = CAShapeLayer()
roundedLayer.fillColor = UIColor.blue.cgColor
roundedLayer.actions = ["hidden": NSNull()]
self.contentView.layer.insertSublayer(roundedLayer, below: self.titleLabel?.layer)
self.roundedLayer = roundedLayer
let todayLayer = CAShapeLayer()
todayLayer.fillColor = UIColor.clear.cgColor
todayLayer.strokeColor = UIColor.orange.cgColor
todayLayer.actions = ["hidden": NSNull()]
self.contentView.layer.insertSublayer(todayLayer, below: self.titleLabel?.layer)
self.todayLayer = todayLayer
self.shapeLayer.isHidden = true
let view = UIView(frame: self.bounds)
self.backgroundView = view
}
override func layoutSubviews() {
super.layoutSubviews()
self.selectionLayer?.frame = self.contentView.bounds
self.roundedLayer?.frame = self.contentView.bounds
self.todayLayer?.frame = self.contentView.bounds
let contentHeight = self.contentView.frame.height
let contentWidth = self.contentView.frame.width
let selectionLayerBounds = selectionLayer?.bounds ?? .zero
let selectionLayerWidth = selectionLayer?.bounds.width ?? .zero
let roundedLayerHeight = roundedLayer?.frame.height ?? .zero
let roundedLayerWidth = roundedLayer?.frame.width ?? .zero
switch selectionType {
case .middle:
self.selectionLayer?.isHidden = false
self.roundedLayer?.isHidden = true
self.todayLayer?.isHidden = true
let selectionRect = selectionLayerBounds
.insetBy(dx: 0.0, dy: 4.0)
self.selectionLayer?.path = UIBezierPath(rect: selectionRect).cgPath
case .leftBorder:
self.selectionLayer?.isHidden = false
self.roundedLayer?.isHidden = false
self.todayLayer?.isHidden = true
let selectionRect = selectionLayerBounds
.insetBy(dx: selectionLayerWidth / 4, dy: 4)
.offsetBy(dx: selectionLayerWidth / 4, dy: 0.0)
self.selectionLayer?.path = UIBezierPath(rect: selectionRect).cgPath
let diameter: CGFloat = min(roundedLayerHeight, roundedLayerWidth)
let rect = CGRect(x: contentWidth / 2 - diameter / 2,
y: contentHeight / 2 - diameter / 2,
width: diameter,
height: diameter)
.insetBy(dx: 2.5, dy: 2.5)
self.roundedLayer?.path = UIBezierPath(ovalIn: rect).cgPath
case .rightBorder:
self.selectionLayer?.isHidden = false
self.roundedLayer?.isHidden = false
self.todayLayer?.isHidden = true
let selectionRect = selectionLayerBounds
.insetBy(dx: selectionLayerWidth / 4, dy: 4)
.offsetBy(dx: -selectionLayerWidth / 4, dy: 0.0)
self.selectionLayer?.path = UIBezierPath(rect: selectionRect).cgPath
let diameter: CGFloat = min(roundedLayerHeight, roundedLayerWidth)
let rect = CGRect(x: contentWidth / 2 - diameter / 2,
y: contentHeight / 2 - diameter / 2,
width: diameter,
height: diameter)
.insetBy(dx: 2.5, dy: 2.5)
self.roundedLayer?.path = UIBezierPath(ovalIn: rect).cgPath
case .single:
self.selectionLayer?.isHidden = true
self.roundedLayer?.isHidden = false
self.todayLayer?.isHidden = true
let diameter: CGFloat = min(roundedLayerHeight, roundedLayerWidth)
let rect = CGRect(x: contentWidth / 2 - diameter / 2,
y: contentHeight / 2 - diameter / 2,
width: diameter,
height: diameter)
.insetBy(dx: 2.5, dy: 2.5)
self.roundedLayer?.path = UIBezierPath(ovalIn: rect).cgPath
case .today:
self.selectionLayer?.isHidden = true
self.roundedLayer?.isHidden = true
self.todayLayer?.isHidden = false
let diameter: CGFloat = min(roundedLayerHeight, roundedLayerWidth)
let rect = CGRect(x: contentWidth / 2 - diameter / 2,
y: contentHeight / 2 - diameter / 2,
width: diameter,
height: diameter)
.insetBy(dx: 2.5, dy: 2.5)
self.todayLayer?.path = UIBezierPath(ovalIn: rect).cgPath
case .none:
self.selectionLayer?.isHidden = true
self.roundedLayer?.isHidden = true
self.todayLayer?.isHidden = true
}
}
}
I have referred lot of stuffs in the stackoverflow and some where else but i could't found the proper result any where.
I also had a look at the above like and some reference but in that case i have the issue of random date selected in the some other random months.