Pageboy

repository·main·Indexed 24 days ago

https://github.com/uias/pageboy

A wrapper around UIPageViewController designed to simplify data source management and enhance delegation. Pageboy provides advanced features such as dynamic insertion and deletion of pages, auto-scrolling via PageboyAutoScroller, infinite scrolling, and custom animated transitions. It includes a specialized data source (PageboyViewControllerDataSource) and delegate (PageboyViewControllerDelegate) for reliable scroll tracking and lifecycle events.

Tokens
2.6K
Snippets
7
Records
15
Agent score
85%

What's inside Pageboy

  1. Implement PageboyViewControllerDataSource

    main

    To use Pageboy, create a subclass of PageboyViewController and assign it a PageboyViewControllerDataSource. You must implement the following three methods to provide your view controllers:

    1. numberOfViewControllers(in:): Returns the total count of pages.
    2. viewController(for:at:): Returns the specific UIViewController for a given PageIndex.
    3. defaultPage(for:): Returns an optional Page to serve as the default page (can return nil).
    class PageViewController: PageboyViewController, PageboyViewControllerDataSource {
    
        override func viewDidLoad() {
            super.viewDidLoad()
    	self.dataSource = self
        }
    }
    
    // Implementation of PageboyViewControllerDataSource
    func numberOfViewControllers(in pageboyViewController: PageboyViewController) -> Int {
        return viewControllers.count
    }
    
    func viewController(for pageboyViewController: PageboyViewController,
                        at index: PageboyViewController.PageIndex) -> UIViewController? {
        return viewControllers[index]
    }
    
    func defaultPage(for pageboyViewController: PageboyViewController) -> PageboyViewController.Page? {
        return nil
    }
  2. Migrate Pageboy Data Source to 2.0

    main

    In Pageboy 2.0, PageboyViewControllerDataSource has been redesigned to support dynamic view controller loading and better performance. Instead of returning a static array of view controllers, you must now implement methods to provide the page count and fetch specific view controllers by index.

    Key changes:

    • Replace viewControllers(forPageboyViewController:) with a combination of numberOfViewControllers(in:) and viewController(for:at:).
    • Update defaultPageIndex(forPageboyViewController:) to defaultPage(for:).
    • Use PageboyViewController.PageIndex (an Int typealias) for index values.
    // Pageboy 2.x implementation
    func numberOfViewControllers(in pageboyViewController: PageboyViewController) -> PageboyViewController.PageIndex {
        return 2
    }
        
    func viewController(for pageboyViewController: PageboyViewController,
                        at index: PageboyViewController.PageIndex) -> UIViewController? {
        return self.viewControllers[index]
    }
    
    func defaultPage(for pageboyViewController: PageboyViewController) -> PageboyViewController.Page? {
        return nil
    }
  3. Migrate PageboyViewControllerDelegate to 2.0

    main

    The PageboyViewControllerDelegate methods have been refactored to support the new data source and updated syntax. When migrating, ensure you update the method signatures for scrolling and reloading events.

    Signature updates:

    • willScrollToPageAt: Uses PageboyViewController.PageIndex instead of Int.
    • didScrollTo: Now includes an animated: Bool parameter.
    • didScrollToPageAt: Uses PageboyViewController.PageIndex instead of Int and includes animated: Bool.
    • didReloadWith: Replaces didReload to provide the currentViewController and currentPageIndex instead of an array of view controllers.
    // Pageboy 2.x Delegate Examples
    
    func pageboyViewController(_ pageboyViewController: PageboyViewController,
                                willScrollToPageAt index: PageboyViewController.PageIndex,
                                direction: PageboyViewController.NavigationDirection,
                                animated: Bool)
    
    func pageboyViewController(_ pageboyViewController: PageboyViewController,
                                didScrollTo position: CGPoint,
                                direction: PageboyViewController.NavigationDirection,
                                animated: Bool)
    
    func pageboyViewController(_ pageboyViewController: PageboyViewController,
                                didScrollToPageAt index: PageboyViewController.PageIndex,
                                direction: PageboyViewController.NavigationDirection,
                                animated: Bool)
    
    func pageboyViewController(_ pageboyViewController: PageboyViewController,
                                didReloadWith currentViewController: UIViewController,
                                currentPageIndex: PageboyViewController.PageIndex)
  4. Enable automatic timer-based scrolling

    main

    Use PageboyAutoScroller to implement automatic page transitions based on a timer. You can enable it directly on the autoScroller property.

    pageboyViewController.autoScroller.enable()
  5. Configure custom animated transitions

    main

    By default, Pageboy uses the standard UIPageViewController animation. You can provide custom animations by setting the .transition property with a Transition object.

    pageboyViewController.transition = Transition(style: .push, duration: 1.0)
  6. Use PageboyViewControllerDelegate for reliable scroll tracking

    main

    The PageboyViewControllerDelegate provides more reliable lifecycle events than standard UIPageViewController. Use these methods to track transitions and current positions:

    • willScrollToPageAt(_:direction:animated:): Called just before a transition begins.
    • didScrollToPosition(_:direction:animated:): Called as the view scrolls to a relative position during a transition.
    • didScrollToPageAt(_:direction:animated:): Called when a scroll transition successfully completes.
    • didReload(with:currentPageIndex:): Called when child view controllers have been reloaded.
  7. Insert and delete pages dynamically

    main

    You can modify the page set at runtime using insertPage(at:then:) and deletePage(at:then:).

    Important: You must update your underlying data source (e.g., your array of view controllers) before calling these methods, similar to how UITableView works.

    After the update, you can specify a PageUpdateBehavior. The default behavior is .scrollToUpdate, which scrolls the view to the location of the change.

    let index = 2
    viewControllers.insert(UIViewController(), at: index)
    pageViewController.insertPage(at: index)
  8. Navigate through pages programmatically

    main

    Use the scrollToPage() method to move between pages. You can use .next or .previous directions.

    Additional configuration:

    • Enable infinite scrolling via .isInfiniteScrollEnabled.
    • Control interactive scrolling via .isScrollEnabled.
    pageViewController.scrollToPage(.next, animated: true)