patchthecode / JTAppleCalendar

The Unofficial Apple iOS Swift Calendar View. Swift calendar Library. iOS calendar Control. 100% Customizable
https://patchthecode.com
MIT License
7.57k stars 808 forks source link

Calendar not resizing cells after trait collection changes #1112

Open LondonAtlas opened 5 years ago

LondonAtlas commented 5 years ago

(Required) Version Number: JTAppleCalendar: 7.1.7 (need to support iOS 12) ipadOS (iOS 13) iPad 11" Simulator iOS 12.4

Description

Calendar doesn't resize cells correctly when transitioning from compactWidth/RegularHeight to RegularWidth/RegularHeight and vice versa.

I am also using the dates to show another view when didSelect is fired. If I adjust the app frame and the tap back to return to the calendar, the layout is also incorrect.

Steps To Reproduce

Use an iPad and add a second app like safari. Rotate iPad so that it is in the landscape orientation Adjust the size of the two apps so the calendar goes from compactWidth/RegularHeight to RegularWidth/RegularHeight (slimmest to widest while a second app is present)

Expected Behavior

Calendar resizes cells so that they fit from edge to edge of the collection view.

Additional Context

UI is laid out using a storyboard with top, bottom, leading, trailing constraints with top, leading, and trailing being set to edges of the viewController's view/ calendar superview.

I have tried calling invalidateLayout on the calendar's collectionViewLayout in the traitCollectionDidChange function but the same problem continues.

In viewDidLoad() I have this set up code:

self.calendar.scrollDirection = .vertical
        self.calendar.scrollingMode = .nonStopToSection(withResistance: 0.5)
        self.calendar.showsVerticalScrollIndicator = false

I have also implemented the following as per the common issues section in the wiki.

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)
        self.reloadCalendar(to: size, with: coordinator)
    }

    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        super.traitCollectionDidChange(previousTraitCollection)
        self.calendar.reloadData(withanchor: self.calendar.visibleDates().monthDates.first?.date)
    }

    func reloadCalendar(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        let visibleDates = self.calendar.visibleDates()
        let date = visibleDates.monthDates.first?.date
        self.calendar.viewWillTransition(to: size, with: coordinator, anchorDate: date)

        DispatchQueue.main.async {
            // adding this because after rotating the current visible dates will shift after the transition method call
            self.calendar.scrollToHeaderForDate(date ?? Date(), withAnimation: false)
        }
    }

P.s. My hunch is I have missed a critical step but after reading the how to create a calendar several times I don't know what I am missing.

patchthecode commented 5 years ago

can you try writing this in your viewController?

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    let visibleDates = calendarView.visibleDates()
    calendarView.viewWillTransition(to: .zero, with: coordinator, anchorDate: visibleDates.monthDates.first?.date)
}

and remove the trait code.

LondonAtlas commented 5 years ago

Thank you for replying so fast!

I updated but the issues remain. Also now when going from the largest width to the smallest the date shifts. For example, if I am looking at August 2019 and make the width smaller the dates shift to April 2001, which was my reasoning for the reload calendar method.

Screen Shot 2019-08-08 at 3 46 06 pm

Screen Shot 2019-08-08 at 3 57 27 pm

patchthecode commented 5 years ago

hmm. that function i gave you was supposed to do it. Is it possible you can provide a sample iPad project replicating the issue?

you do not have to design it or any thing. i'll see how i can fix on my end.

LondonAtlas commented 5 years ago

jtapplecalendar.zip

For personal pride I must tell you that I don't throw all my code into a single view controller file lol.

Thank you again for taking a look. The easiest way to replicate is to tap a date, while the detail view is present expand or compress the app and then navigate back to the calendar.

LondonAtlas commented 5 years ago

Is there anything I can do to help fix this issue?

patchthecode commented 5 years ago

Apologies. I missed this issue.. taking a look. (got caught up between projects)

patchthecode commented 5 years ago

My observations

  1. With the split view, the cells resize correctly with the code i gave you ✅

  2. With the code i gave you, (without and plist view), if you just rotate the calendar horizontally, and then vertically, it snaps to an incorrect date ❗️
    This behaviour is incorrect. Investigating if this was introduced with the iOS 13.

patchthecode commented 5 years ago

As a work around, can you give the calendar's bottom constraint an explicit height, instead of making it dynamically reach the bottom of the viewController?

LondonAtlas commented 5 years ago

Apologies for the long delay. I have set the bottom constraint to the safe area of the superview but rotating the device still results in the date offset being wrong.

I have also tried forcing a height during viewWillAppear, and updating the height constraint viewWillTransition and traitCollectionDidChange but now when I rotate to landscape or portraiture calendar's dates don't fit into the new size.

rs658726 commented 3 years ago

@LondonAtlas I'm able to successfully resize my calendar after adding these lines to the viewWillTransition function:

DispatchQueue.main.async {
     self.calendar.viewWillTransition(to: CGSize(width: .zero, height: self.calendar.frame.width), with: coordinator, anchorDate: visibleDates.monthDates.first?.date)
}