Swift FSCalendar select date in calendar display event in tableview

8k views Asked by At

I am working with FSCalendar for my application. I am needing help listing the specific events from my collection view in my calendar and showing in the tableview below it. So when the user clicks on a cell (i.e. a date) on the calendar. The tableview will update and display the specific event for that day. I have checked the documentation for this and there is none for this specific task and i have looked at several other places. I would be grateful for some code examples as i am very new to using FSCalendar and implementing it. Thanks

My current app page:

enter image description here

some of my relevant code:

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, FSCalendarDelegate, FSCalendarDataSource, FSCalendarDelegateAppearance, UIGestureRecognizerDelegate {

    
    @IBOutlet weak var tableView: UITableView!
    @IBOutlet weak var calendar: FSCalendar!
    @IBOutlet weak var animationSwitch: UISwitch!
    @IBOutlet weak var calendarHeightConstraint: NSLayoutConstraint!

    
    fileprivate let gregorian: Calendar = Calendar(identifier: .gregorian)
    
    var datesWithEvent = ["2020-12-23","2020-12-16","2020-12-18","2020-12-14","2020-12-06"]
    var datesWithMultipleEvents = ["2020-12-03","2020-12-13","2020-12-11","2020-10-03","2020-12-06"]
    
    fileprivate lazy var dateFormatter2: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd"
        return formatter
    }()

override func viewDidLoad() {
        super.viewDidLoad()
        
        calendar.select(Date())
        
        self.view.addGestureRecognizer(self.scopeGesture)
        self.tableView.panGestureRecognizer.require(toFail: self.scopeGesture)
        calendar.scope = .week
//        calendar.scrollDirection = .horizontal
        calendar.accessibilityIdentifier = "calendar"

    }

func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
        print("did select date \(self.dateFormatter2.string(from: date))")
        let selectedDates = calendar.selectedDates.map({self.dateFormatter2.string(from: $0)})
        print("selected dates is \(selectedDates)")
        if monthPosition == .next || monthPosition == .previous {
            calendar.setCurrentPage(date, animated: true)
        }
    }
    
    
    func calendarCurrentPageDidChange(_ calendar: FSCalendar) {
        print("\(self.dateFormatter2.string(from: calendar.currentPage))")
    }
    
    func numberOfSections(in tableView: UITableView) -> Int {
        return 2
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return [2,20] [section]
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if indexPath.section == 0 {
            let identifier = ["cell_month", "cell_week"][indexPath.row]
            let cell = tableView.dequeueReusableCell(withIdentifier: identifier)!
            return cell
        } else {
            let cell = tableView.dequeueReusableCell(withIdentifier: "cell")!
            
            return cell
        }
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
        if indexPath.section == 0 {
            let scope: FSCalendarScope = (indexPath.row == 0) ? .month : .week
            self.calendar.setScope(scope, animated: self.animationSwitch.isOn)
        }
    }
    
    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return 10
    }
    
    @IBAction func toggleClicked(sender: AnyObject) {
        if self.calendar.scope == .month {
            self.calendar.setScope(.week, animated: self.animationSwitch.isOn)
        }else {
            self.calendar.setScope(.month, animated: self.animationSwitch.isOn)
        }
        
    }
    
    
    
    func calendar(_ calendar: FSCalendar, numberOfEventsFor date: Date) -> Int {

        let dateString = dateFormatter2.string(from: date)
                
        if self.datesWithEvent.contains(dateString){
            return 1
        }
        
        if self.datesWithMultipleEvents.contains(dateString) {
            return 2
        }
        
        return 0
    }
    
    
    func calendar(_ calendar: FSCalendar, appearance: FSCalendarAppearance, eventDefaultColorsFor date: Date) -> [UIColor]? {
        
        let key = self.dateFormatter2.string(from: date)
        
        if self.datesWithMultipleEvents.contains(key){
            return [UIColor.blue]
        }
        return nil
    }
    
}
1

There are 1 answers

5
TinaDitte On BEST ANSWER

I did it this way: In my "didSelect date" method I reformat the date and then I call a handler for Firebase, where I search for the specific date. I use a wherefield method for Firebase, that searches all events matching that date. Those events get listed in an array. I then use that array for listing the wanted events.

In my Viewcontroller

 func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
        let formatter = DateFormatter()
        formatter.dateFormat = "dd/MM-yyyy"
        let result = formatter.string(from: date)
        EventHandler.readEventAtDate(date: result, tableView: eventTable)
    }

In my handler:

 static func readEventAtDate(date: String, tableView: UITableView) {
    //To feed tableview with specific date
    database.collection("Events").whereField("date", isEqualTo: date).getDocuments { (query, error) in
        if error != nil {
            print("Error: \(String(describing: error))")
        } else {
            self.eventByDate.removeAll()
                for event in query!.documents {
                    let map = event.data()
                    let header = map["header"] as! String
                    let text = map["text"] as! String
                    let place = map["place"] as! String
                    let responsible = map["responsible"] as! String
                    let time = map["time"] as! String
                    let date = map["date"] as! String
                    let coordinates = map["coordinates"] as! GeoPoint
                    
                    let readEvent = Event(eventID: event.documentID, header: header, text: text, place: place, responsible: responsible, time: time, date: date, coordinates: coordinates)
                    eventByDate.append(readEvent)
                }
            DispatchQueue.main.async {
                tableView.reloadData()
            }
        }
    }
}

In my tableview

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return EventHandler.eventByDate.count
}