0

My project is an eBook-reader (ePub) with UIPageViewController holding webViews to show the pages.
The pages are computed by loading a webView with a chapterFile and counting the pages the webView needs to display in webViewDidFinishLoad. This will be done for all chapterFiles in a delegate called trough webViewDidFinishLoad, where the next chapter will be loaded in a webView to compute the pages.
On certain conditions, like turning from portrait to landscape with new textSize in portrait, the pageViewController is demanding a second page faster than the paging needs to finish.
PageViewController is calling

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController

In this method I am calling another method "goToNextPage" to look if the next Page is a shift of the webViews viewPort or an new chapterFile to load.
What I want is "goToNextPage" to wait for the paging to be done.

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController   viewControllerAfterViewController:(UIViewController *)viewController{
     ...
    //paging is already in progress at this point (if needed )
    //I want goToNextPage to wait for paging to be finished 
    [self goToNextPage];`
     ...
    //loading newViewController with right page
    return newViewController;
}

I don't know how to achieve this because of the delegate calls to wait for.

Yedy
  • 2,107
  • 1
  • 25
  • 30

1 Answers1

0

I have worked on a similar project. We found that it was necessary to calculate pages behind the scenes for performance. We have a web view sized the same as it would be in the UIPageViewController placed behind the UIPageViewController so that it is not visible (setting the view to hidden causes it to not lay out the web page). Then we cycle through each spine item calculating the page count and save the spine item index, current font size, and the page count for use later. In our case it was possible to provide some amount of navigation as pages are calculated (similar to iBooks) without preventing all navigation.

Once page counts are calculated, you have all of the information necessary to display any page at any point even if the current page is not yet complete in loading.

If font size or view size changes, page counts will need to be recalculated.

Another option could be to prevent page changes until the current spine item has finished calculating pages. You can accomplish that by returning nil from pageViewController:viewControllerAfterViewController: and pageViewController:viewControllerBeforeViewController: until your page count comes back. Pages will likely calculate fast enough that it will just appear that the page turn is rate limited.

One of the benefits to calculating the size of all spine items before-hand is that navigation by more than one page at a time becomes possible.

Either way you go, I do recommend rate limiting the page turn -- I have run into some issues with the web view crashing in setDeviceScaleFactor if pages are turned too quickly when in a UIPageViewController. The UIPageViewController will attempt to ask for new view controllers much faster than the device can keep up with creating and rendering UIWebViews if a user continually turns pages as fast as possible.

mwu
  • 472
  • 6
  • 13
  • Thanks for the detailed answer. I also use a hidden webView to calculate and keep the pages per spine. The problem, when recalculation is needed, and device is in landscape (with two pages), the secondView is demanded faster than the calculation takes. Even when I only calcutate the spine needed it is to slow. Returning nil when calculation still in progress would cause the second page not to show, and the pageViewController would not ask a second time, or am I wrong? Waiting for paging to complete before returning the next view is exactly what I want. – Yedy Mar 21 '14 at 07:50