I have a form in which the user will select days and then select a date from calendar view..
for example: the user will first select sun and mon .. then click on date button an so calendar view will be shown ..
I want the user just be able to select dates in days sun or mon .. i want to disable the other days and highlight them for example ..
what is the best way to do that?
i saw these two libraries:
https://cocoapods.org/pods/JTAppleCalendar
https://github.com/WenchaoD/FSCalendar
but didn't find anything that helps me do what i need using them..
what is the best way to do that?
You have to consider Sunday as 1, Monday as 2, Tuesday as 3 and so on Saturday 7.
Define below globally
fileprivate let gregorian: Calendar = Calendar(identifier: .gregorian)
fileprivate lazy var dateFormatter2: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
return formatter
}()
var arrDates = NSMutableArray()
Write below line in viewDidLoad
.
arrDates = self.getUserSelectedDates([1, 2], calender: self.calendarVW)
Here 1, 2 means user selected Monday and Tuesday (so This array contains only those dates which are Sunday and Monday)
Below is Function that returns Dates array Based on Day value like 1,2 and so on till 7.
func getUserSelectedDates(_ arrWeekDay: [Int], calender calenderVW: FSCalendar?) -> NSMutableArray {
let arrUnAvailibilityDates = NSMutableArray()
let currentDate: Date? = calenderVW?.currentPage
//get calender
let gregorianCalendar = Calendar.init(identifier: .gregorian)
// Start out by getting just the year, month and day components of the current date.
var components: DateComponents? = nil
if let aDate = currentDate {
components = gregorianCalendar.dateComponents([.year, .month, .day, .weekday], from: aDate)
}
// Change the Day component to 1 (for the first day of the month), and zero out the time components.
components?.day = 1
components?.hour = 0
components?.minute = 0
components?.second = 0
//get first day of current month
var firstDateOfCurMonth: Date? = nil
if let aComponents = components {
firstDateOfCurMonth = gregorianCalendar.date(from: aComponents)
}
//create new component to get weekday of first date
var newcomponents: DateComponents? = nil
if let aMonth = firstDateOfCurMonth {
newcomponents = gregorianCalendar.dateComponents([.year, .month, .day, .weekday], from: aMonth)
}
let firstDateWeekDay: Int? = newcomponents?.weekday
//get last month date
let curMonth: Int? = newcomponents?.month
newcomponents?.month = (curMonth ?? 0) + 1
var templastDateOfCurMonth: Date? = nil
if let aNewcomponents = newcomponents {
templastDateOfCurMonth = gregorianCalendar.date(from: aNewcomponents)?.addingTimeInterval(-1)
}
// One second before the start of next month
var lastcomponents: DateComponents? = nil
if let aMonth = templastDateOfCurMonth {
lastcomponents = gregorianCalendar.dateComponents([.year, .month, .day, .weekday], from: aMonth)
}
lastcomponents?.hour = 0
lastcomponents?.minute = 0
lastcomponents?.second = 0
var lastDateOfCurMonth: Date? = nil
if let aLastcomponents = lastcomponents {
lastDateOfCurMonth = gregorianCalendar.date(from: aLastcomponents)
}
var dayDifference = DateComponents()
dayDifference.calendar = gregorianCalendar
if arrWeekDay.count == 0 {
} else if arrWeekDay.count == 1 {
let wantedWeekDay = Int(arrWeekDay[0])
var firstWeekDateOfCurMonth: Date? = nil
if wantedWeekDay == firstDateWeekDay {
firstWeekDateOfCurMonth = firstDateOfCurMonth
} else {
var day: Int = wantedWeekDay - firstDateWeekDay!
if day < 0 {
day += 7
}
day += 1
components?.day = day
firstWeekDateOfCurMonth = gregorianCalendar.date(from: components!)
}
var weekOffset: Int = 0
var nextDate: Date? = firstWeekDateOfCurMonth
repeat {
let strDT: String = getSmallFormatedDate(convertCalendarDate(toNormalDate: nextDate))!
arrUnAvailibilityDates.add(strDT)
weekOffset += 1
dayDifference.weekOfYear = weekOffset
var date: Date? = nil
if let aMonth = firstWeekDateOfCurMonth {
date = gregorianCalendar.date(byAdding: dayDifference, to: aMonth)
}
nextDate = date
} while nextDate?.compare(lastDateOfCurMonth!) == .orderedAscending || nextDate?.compare(lastDateOfCurMonth!) == .orderedSame
}
else {
for i in 0..<arrWeekDay.count {
let wantedWeekDay = Int(arrWeekDay[i])
var firstWeekDateOfCurMonth: Date? = nil
if wantedWeekDay == firstDateWeekDay {
firstWeekDateOfCurMonth = firstDateOfCurMonth
} else {
var day: Int = wantedWeekDay - firstDateWeekDay!
if day < 0 {
day += 7
}
day += 1
components?.day = day
firstWeekDateOfCurMonth = gregorianCalendar.date(from: components!)
}
var weekOffset: Int = 0
var nextDate: Date? = firstWeekDateOfCurMonth
repeat {
let strDT = getSmallFormatedDate(convertCalendarDate(toNormalDate: nextDate))
arrUnAvailibilityDates.add(strDT!)
weekOffset += 1
dayDifference.weekOfYear = weekOffset
var date: Date? = nil
if let aMonth = firstWeekDateOfCurMonth {
date = gregorianCalendar.date(byAdding: dayDifference, to: aMonth)
}
nextDate = date
} while nextDate?.compare(lastDateOfCurMonth!) == .orderedAscending || nextDate?.compare(lastDateOfCurMonth!) == .orderedSame
}
}
return arrUnAvailibilityDates
}
func getSmallFormatedDate(_ localDate: Date?) -> String? {
let dateFormatter = DateFormatter()
let timeZone = NSTimeZone(name: "UTC")
if let aZone = timeZone {
dateFormatter.timeZone = aZone as TimeZone
}
dateFormatter.dateFormat = "yyyy-MM-dd"
var dateString: String? = nil
if let aDate = localDate {
dateString = dateFormatter.string(from: aDate)
}
return dateString
}
func convertCalendarDate(toNormalDate selectedDate: Date?) -> Date? {
let sourceTimeZone = NSTimeZone(abbreviation: "UTC")
let destinationTimeZone = NSTimeZone.system as NSTimeZone
var sourceGMTOffset: Int? = nil
if let aDate = selectedDate {
sourceGMTOffset = sourceTimeZone?.secondsFromGMT(for: aDate)
}
var destinationGMTOffset: Int? = nil
if let aDate = selectedDate {
destinationGMTOffset = destinationTimeZone.secondsFromGMT(for: aDate)
}
let interval1 = TimeInterval((destinationGMTOffset ?? 0) - (sourceGMTOffset ?? 0))
var localDate: Date? = nil
if let aDate = selectedDate {
localDate = Date(timeInterval: interval1, since: aDate)
}
return localDate
}
Below is FSCalendar delegates
extension ViewController: FSCalendarDelegate, FSCalendarDataSource, FSCalendarDelegateAppearance {
func calendar(_ calendar: FSCalendar, boundingRectWillChange bounds: CGRect, animated: Bool) {
self.view.layoutIfNeeded()
}
func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
}
func calendarCurrentPageDidChange(_ calendar: FSCalendar) {
arrDates = self.getUserSelectedDates([3, 4], calender: self.calendarVW)
}
func calendar(_ calendar: FSCalendar, appearance: FSCalendarAppearance, titleDefaultColorFor date: Date) -> UIColor? {
if arrDates.contains(dateFormatter2.string(from: date)) {
return UIColor.green
} else {
return UIColor.red
}
}
func calendar(_ calendar: FSCalendar, shouldSelect date: Date, at monthPosition: FSCalendarMonthPosition) -> Bool {
if arrDates.contains(dateFormatter2.string(from: date)) {
return true
}
else {
return false
}
}
}