Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JTAppleCalendar Custom cell bug on cellForItemAt date in Swift 3.2

I added JTAppleCalendar inside my project and I want to add some tags in some of my calendar cells. I have success adding them, but when I scroll left or right on my calendar months, cells inside tags disappear, hide, or mix, and when I scroll again and again there is more and more mixing. Do I need any protocols or delegates, etc.? Or, it is just a bug?

How can I fix that bug?

My example GitHub project

My cellForItemAt code:

func calendar(_ calendar: JTAppleCalendarView, cellForItemAt date: Date, cellState: CellState, indexPath: IndexPath) -> JTAppleCell {
        let cell = calendar.dequeueReusableCell(withReuseIdentifier: "CellView", for: indexPath) as! CellView

        var currentdate = String(describing: myCalendar.date(byAdding: .day, value: 1, to: cellState.date))
        currentdate = currentdate.substring(from: 9, length: 10)


        cell.tagList.tags.removeAll()
        cell.tagList.hide()
        cell.contentView.backgroundColor = nil
        cell.tagList.alpha = 0
        cell.tagList.numberOfRows = 0
        cell.tagList.backgroundColor = UIColor.clear
        cell.tagList.isHidden = true


        var i : Int
        i = 0

        for object in datas {

        i =  i + 1

                let clean = "\(object)".components(separatedBy: "*")

                if clean[0] == currentdate {
                   let gotag : Int
                    gotag = Int(clean[1])!
                    cell.tagList.isHidden = false
                    cell.dayLabel.text = cellState.text
                    cell.contentView.backgroundColor = UIColor.gray

                    let itemName = "Item name  \(i)"


                        cell.tagList.alpha = 1

                        if clean[1] == "1" {

                                cell.tagList.addTag(itemName, target: self, tapAction: #selector(ViewController.tap(_:)), longPressAction: #selector(ViewController.tap(_:)),backgroundColor: UIColor.orange,textColor: UIColor.white,comesTag: gotag)


                        }else if clean[1] == "2" {

                                cell.tagList.addTag(itemName, target: self, tapAction: #selector(ViewController.tap(_:)), longPressAction: #selector(ViewController.tap(_:)),backgroundColor: UIColor.green,textColor: UIColor.white,comesTag: gotag)

                        }else if clean[1] == "3" {

                                 cell.tagList.addTag(itemName, target: self, tapAction: #selector(ViewController.tap(_:)), longPressAction: #selector(ViewController.tap(_:)),backgroundColor: UIColor.brown,textColor: UIColor.white,comesTag: gotag)

                        }else if clean[1] == "4" {

                              cell.tagList.addTag(itemName, target: self, tapAction: #selector(ViewController.tap(_:)), longPressAction: #selector(ViewController.tap(_:)),backgroundColor: UIColor.black,textColor: UIColor.white,comesTag: gotag)
                        }



            }else{

                cell.tagList.backgroundColor = UIColor.clear
        }





        }


        handleCellConfiguration(cell: cell, cellState: cellState)
        return cell
    }

Bug in action:

https://github.com/LetSwiftDev/CalendarBug/blob/master/calendarbug.gif

Also you can join official JTAppleCalendar chat here https://gitter.im/patchthecode/JTAppleCalendar

like image 820
SwiftDeveloper Avatar asked Nov 25 '17 11:11

SwiftDeveloper


1 Answers

Basically, to make a weird "workaround" you should implement the classic UICollectionView (JTAppleCalendar comes from it) willDisplay method, that , as you can see , in theory it should be used to detect cell additions instead of replicate it's content, so to make this re-build of content you can follow the example also explained to the JTAppleCalendar gitHub issues and reported by swift nub here in this page.

So, your code could be:

ViewController.swift:

extension ViewController: JTAppleCalendarViewDelegate, JTAppleCalendarViewDataSource {
    func calendar(_ calendar: JTAppleCalendarView, willDisplay cell: JTAppleCell, forItemAt date: Date, cellState: CellState, indexPath: IndexPath) {
        var cell = cell as! CellView
        cell = sharedFunctionToConfigureCell(cell: cell, cellState: cellState, date: date)
    }

    func calendar(_ calendar: JTAppleCalendarView, cellForItemAt date: Date, cellState: CellState, indexPath: IndexPath) -> JTAppleCell {
        var cell = calendar.dequeueReusableCell(withReuseIdentifier: "CellView", for: indexPath) as! CellView
        cell = sharedFunctionToConfigureCell(cell: cell, cellState: cellState, date: date)
        return cell
    }

    func sharedFunctionToConfigureCell(cell: CellView, cellState: CellState, date: Date)-> CellView {
        var currentdate = String(describing: myCalendar.date(byAdding: .day, value: 1, to: cellState.date))
        currentdate = currentdate.substring(from: 9, length: 10)
        cell.tagList.tags.removeAll()
        cell.tagList.hide()
        cell.contentView.backgroundColor = nil
        cell.tagList.alpha = 0
        cell.tagList.numberOfRows = 0
        cell.tagList.backgroundColor = UIColor.clear
        cell.tagList.isHidden = true
        var i : Int
        i = 0
        for object in datas {
            i =  i + 1
            let clean = "\(object)".components(separatedBy: "*")
            if clean[0] == currentdate {
                let gotag : Int
                gotag = Int(clean[1])!
                cell.tagList.isHidden = false
                cell.dayLabel.text = cellState.text
                cell.contentView.backgroundColor = UIColor.gray
                let itemName = "Item name  \(i)"
                cell.tagList.alpha = 1
                if clean[1] == "1" {
                    cell.tagList.addTag(itemName, target: self, tapAction: #selector(ViewController.tap(_:)), longPressAction: #selector(ViewController.tap(_:)),backgroundColor: UIColor.orange,textColor: UIColor.white,comesTag: gotag)
                }else if clean[1] == "2" {
                    cell.tagList.addTag(itemName, target: self, tapAction: #selector(ViewController.tap(_:)), longPressAction: #selector(ViewController.tap(_:)),backgroundColor: UIColor.green,textColor: UIColor.white,comesTag: gotag)
                }else if clean[1] == "3" {
                    cell.tagList.addTag(itemName, target: self, tapAction: #selector(ViewController.tap(_:)), longPressAction: #selector(ViewController.tap(_:)),backgroundColor: UIColor.brown,textColor: UIColor.white,comesTag: gotag)
                }else if clean[1] == "4" {
                    cell.tagList.addTag(itemName, target: self, tapAction: #selector(ViewController.tap(_:)), longPressAction: #selector(ViewController.tap(_:)),backgroundColor: UIColor.black,textColor: UIColor.white,comesTag: gotag)
                }
            }else{
                cell.tagList.backgroundColor = UIColor.clear
            }
        }
        handleCellConfiguration(cell: cell, cellState: cellState)
        return cell
    }

    // your other code..

Update (after your tests):

After your comments, I've decided to analyze in deep your code.

First of all, there is a little bug in your mainStoryBoard and you can easily correct it replacing DesignableButton (unexistent class) with UIButton as showed in this pic to avoid the error : CalendarBug[9879:1645088] Unknown class _TtC11CalendarBug16DesignableButton in Interface Builder file.

enter image description here

After, the full JTAppleCaledar library seems hasn't any problem, in fact the author have extended also the willDisplay delegate that solved many issues around rendering of cells.

I've found your problem in the TagListView.swift class, more precisely in the method reset.

TagListView.swift:

func reset() {
  for tag in tags {
      tag.removeFromSuperview()
  }
  tags = []
  currentRow = 0
  numberOfRows = 0
}

This method remove all the tags list (the array of labels) from superview but not the other tags added in past to the superview, in other words only tags contained in the array tags. So, to avoid this issue you can reinforce your reset method by adding on line (we know they are UILabel so it's not needed to know all their tag number):

func reset() {
  for tag in tags {
      tag.removeFromSuperview()
  }
  tags = []
  currentRow = 0
  numberOfRows = 0
  self.subviews.forEach({ if $0 is UILabel { $0.removeFromSuperview()} })
}

To optimize your code you simply correct this method as:

func reset(){
    tags = []
    currentRow = 0
    numberOfRows = 0
    self.subviews.forEach({ if $0 is UILabel { $0.removeFromSuperview()} })
}

Output:

enter image description here

like image 134
Alessandro Ornano Avatar answered Oct 13 '22 01:10

Alessandro Ornano