// // WRPageViewController.h // WeRead (微信读书) // // Reverse-engineered header reconstruction. // Based on UIPageViewController. Supports UIPageCurl (simulation) and // Scroll (slide) page turning styles. Includes fault detection and // patching mechanisms for known UIPageViewController bugs. // #import @class WRPageView; @class WRChapterData; NS_ASSUME_NONNULL_BEGIN // ============================================================================ #pragma mark - Page Flipping Style // ============================================================================ /// The visual style used when transitioning between pages. typedef NS_ENUM(NSInteger, WRPageFlippingStyle) { WRPageFlippingStyleCurl = 0, // UIPageCurl simulation (paper fold) WRPageFlippingStyleSlide = 1, // UIScrollView-based horizontal slide WRPageFlippingStyleFade = 2, // Crossfade transition WRPageFlippingStyleNone = 3, // Instant switch, no animation }; // ============================================================================ #pragma mark - WRPageViewControllerDelegate // ============================================================================ @protocol WRPageViewControllerDelegate @optional /// Called when the page view controller transitions to a new page. - (void)pageViewController:(WRPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed; /// Called before a page transition begins. - (void)pageViewController:(WRPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers; /// Called to determine the spine location for interface orientation changes. - (UIPageViewControllerSpineLocation)pageViewController:(WRPageViewController *)pageViewController spineLocationForInterfaceOrientation:(UIInterfaceOrientation)orientation; /// Called when the current page index changes. - (void)pageViewController:(WRPageViewController *)pageViewController didChangePageIndex:(NSUInteger)pageIndex; @end // ============================================================================ #pragma mark - WRPageViewControllerDataSource // ============================================================================ @protocol WRPageViewControllerDataSource /// Returns the view controller before the given one (for right-to-left paging). - (nullable UIViewController *)pageViewController:(WRPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController; /// Returns the view controller after the given one (for left-to-right paging). - (nullable UIViewController *)pageViewController:(WRPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController; @end // ============================================================================ #pragma mark - WRPageViewController // ============================================================================ @interface WRPageViewController : UIViewController // ---- Delegates ---- @property (nonatomic, weak, nullable) id pageDelegate; @property (nonatomic, weak, nullable) id pageDataSource; // ---- Configuration ---- /// The current page flipping style. @property (nonatomic, assign) WRPageFlippingStyle pageFlippingStyle; /// Whether the user can interact to change pages. @property (nonatomic, assign) BOOL pagingEnabled; /// The underlying UIPageViewController used for page curl and scroll styles. @property (nonatomic, strong, readonly) UIPageViewController *uiPageViewController; // ---- State ---- /// The currently visible page index (0-based within the current chapter). @property (nonatomic, assign, readonly) NSUInteger currentPageIndex; /// Whether a page transition is currently in progress. @property (nonatomic, assign, readonly) BOOL isTransitioning; // ============================================================================ #pragma mark - Initialization // ============================================================================ /// Designated initializer. /// @param delegate The page delegate. /// @param pageType The UIPageViewControllerTransitionStyle (curl or scroll). /// @param flippingStyle The WRPageFlippingStyle to use. - (instancetype)initWithDelegate:(id)delegate withPageType:(UIPageViewControllerTransitionStyle)pageType pageFlippingStyle:(WRPageFlippingStyle)flippingStyle; // ============================================================================ #pragma mark - Page Navigation // ============================================================================ /// Sets the current page index, optionally animated. - (void)setCurrentPageIndex:(NSUInteger)pageIndex animated:(BOOL)animated; /// Advances to the next page. Returns YES if successful, NO if at the end. - (BOOL)goToNextPageAnimated:(BOOL)animated; /// Goes back to the previous page. Returns YES if successful, NO if at the beginning. - (BOOL)goToPreviousPageAnimated:(BOOL)animated; /// Replaces the currently displayed view controllers. - (void)setViewControllers:(NSArray *)viewControllers direction:(UIPageViewControllerNavigationDirection)direction animated:(BOOL)animated completion:(void (^ __nullable)(BOOL finished))completion; // ============================================================================ #pragma mark - Fault Detection & Patching // ============================================================================ /// /// Detects a navigation direction crash in UIPageViewController's /// queuingScrollView:didScrollWithAnimation: callback. /// /// This addresses a known Apple bug where the internal /// UIPageViewControllerQueuingScrollView can enter an inconsistent state /// and crash with an invalid navigation direction. /// /// @param pageVC The UIPageViewController to check. /// @param queuingScrollView The internal queuing scroll view (if accessible). /// @param methodDidScroll Whether this is called from the didScroll callback. /// @param force Force the detection even if already patched. /// @param logDetail Whether to log detailed diagnostic info. /// @param logCrashReason Whether to log the crash reason string. /// @return YES if a fault was detected (and hopefully patched). /// + (BOOL)detectNavigationDirectionCrashWithPageViewController:(UIPageViewController *)pageVC queuingScrollView:(UIScrollView *)queuingScrollView inMethodDidScrollWithAnimation:(BOOL)methodDidScroll force:(BOOL)force logDetail:(BOOL)logDetail logCrashReason:(BOOL)logCrashReason; /// /// Patches the navigation direction fault by swizzling or resetting /// the internal state of UIPageViewController. + (void)patchNavigationDirectionFault; /// /// Patches the "no view controller managing page view" fault. /// This occurs when UIPageViewController loses track of its child VCs. + (void)patchNoViewControllerManagingPageViewFault; /// /// Patches the UIPageCurl animation fault that can cause visual glitches /// or crashes during rapid page flipping. + (void)patchUIPageCurlFault; @end NS_ASSUME_NONNULL_END