Reputation: 5332
My app has a journal in it that is controlled by a UIPageViewController
. The view controller for the page works fine, but the UIPageViewController
has some erratic behaviour. First, the delegate methods (The page view controller is it's own delegate):
private func journalPage(for date: Date) -> JournalViewController? {
// Create a new view controller and pass suitable data.
guard let journalPage = storyboard?.instantiateViewController(withIdentifier: JournalViewController.storyboardID) as? JournalViewController else {
return nil
}
journalPage.date = date
return journalPage
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
guard let yesterday = calendar.date(byAdding: .day, value: -1, to: self.date) else {
return nil
}
self.date = calendar.startOfDay(for: yesterday)
return journalPage(for: self.date)
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
guard let tomorrow = calendar.date(byAdding: .day, value: 1, to: self.date) else {
return nil
}
self.date = calendar.startOfDay(for: tomorrow)
return journalPage(for: self.date)
}
I update the date
of the UIPageViewController
and then return a configured journal page. The problem is that the there is often duplicate pages (pages for the same date), or a page/date is skipped. I found this question, but don't see how I can implement something similar.
I've worked with UIPageViewController
before and have always used an index to get around this, but in this case an index doesn't make sense as you can scroll to the beginning/end of time (literally).
How can I ensure that a new page is made at the correct time to avoid duplicate/missed dates?
Upvotes: 0
Views: 3876
Reputation: 5332
I solved the problem without using an index (the date
property on the pages is sufficient). This infinitely scrolls in either direction without creating duplicates or skipping pages.
extension JournalPageViewController: UIPageViewControllerDataSource {
/// Creates and returns a JournalViewController if it can be found in the storyboard,
/// and sets it's date to `date`
private func journalPage(for date: Date) -> JournalViewController? {
// Create a new view controller and pass suitable data.
guard let journalPage = storyboard?.instantiateViewController(withIdentifier: JournalViewController.storyboardID) as? JournalViewController else {
return nil
}
journalPage.date = date
return journalPage
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
debugPrint("Before: ", separator: "", terminator: "")
let today = (viewController as! JournalViewController).date
guard var yesterday = calendar.date(byAdding: .day, value: -1, to: today) else {
return nil
}
yesterday = calendar.startOfDay(for: yesterday)
return journalPage(for: yesterday)
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
debugPrint("After: ", separator: "", terminator: "")
let today = (viewController as! JournalViewController).date
guard var tomorrow = calendar.date(byAdding: .day, value: 1, to: today) else {
return nil
}
tomorrow = calendar.startOfDay(for: tomorrow)
return journalPage(for: tomorrow)
}
}
extension JournalPageViewController: UIPageViewControllerDelegate {
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
self.date = (self.viewControllers?.first as! JournalViewController).date
}
}
Upvotes: 3
Reputation: 131461
Couldn't you use the Juilan Day Number (JDN) as an index number?
Upvotes: 0
Reputation: 11646
I think You must model your data in another way, so create a model containing an array with your data, and (for example) use an index to access dato to fill controller. in this way you uniquely access data.
I did so in a PageController-base app, starting from apple sample.
I have a class: (see apple template to compare..)
class ModelController: NSObject, UIPageViewControllerDataSource {
var myPages : [Page]?
.. }
where Page is the class describing you single page. I modified apple code in this way:
func viewControllerAtIndex(_ index: Int) -> BaseHWTestController? {
// Return the data view controller for the given index.
let count = selected.count
if (count == 0) || (index >= count) {
return nil
}
// Create a new view controller and pass suitable data.
let myController = storyboard.instantiateViewController(withIdentifier: identifier) as! CustomPageController
// set ref. to data inside the controller:
BaseHWTestController.dataObject = myPages[index]
return BaseHWTestController
}
Upvotes: 0