139 lines
6.1 KiB
Swift
139 lines
6.1 KiB
Swift
import UIKit
|
||
|
||
/// UIPageViewController 数据源和代理实现
|
||
/// 处理仿真翻页模式下的页面数据供给和翻页事件
|
||
extension RDReaderView: UIPageViewControllerDataSource, UIPageViewControllerDelegate {
|
||
|
||
/// 创建指定页码的子控制器
|
||
/// 空白页返回空视图,正常页从缓存或数据源获取内容
|
||
private func makeSinglePageChildVC(for pageNum: Int) -> RDReaderPageChildViewController {
|
||
if pageNum == RDReaderView.blankPageNum || pageNum == RDReaderView.blankEndPageNum {
|
||
return RDReaderPageChildViewController(contentView: UIView(), pageNum: pageNum)
|
||
}
|
||
let contentView = pageViewForDisplay(pageNum: pageNum)
|
||
return RDReaderPageChildViewController(contentView: contentView, pageNum: pageNum)
|
||
}
|
||
|
||
/// 计算某页的"下一页"页码
|
||
/// 考虑封面页独占和末尾空白页配对的情况
|
||
private func nextPageNum(after pageNum: Int, isDualPage: Bool) -> Int? {
|
||
let totalPages = numberOfPages()
|
||
|
||
// 末尾空白页之后没有更多页
|
||
if pageNum == RDReaderView.blankEndPageNum {
|
||
return nil
|
||
}
|
||
|
||
if isDualPage, let coverIndex = coverPageIndex {
|
||
if pageNum == coverIndex {
|
||
return RDReaderView.blankPageNum
|
||
}
|
||
if pageNum == RDReaderView.blankPageNum {
|
||
let firstContent = coverIndex + 1
|
||
return firstContent < totalPages ? firstContent : nil
|
||
}
|
||
}
|
||
|
||
let next = pageNum + 1
|
||
if next < totalPages {
|
||
return next
|
||
}
|
||
|
||
// pageNum 是最后一页,检查在双页模式下是否需要空白页配对
|
||
if isDualPage {
|
||
if let coverIndex = coverPageIndex {
|
||
let adjustedIndex = pageNum - (coverIndex + 1)
|
||
if adjustedIndex >= 0 && adjustedIndex % 2 == 0 {
|
||
return RDReaderView.blankEndPageNum
|
||
}
|
||
} else {
|
||
if pageNum % 2 == 0 {
|
||
return RDReaderView.blankEndPageNum
|
||
}
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
/// 计算某页的"上一页"页码
|
||
/// 考虑封面页独占和末尾空白页配对的情况
|
||
private func prevPageNum(before pageNum: Int, isDualPage: Bool) -> Int? {
|
||
if pageNum == RDReaderView.blankEndPageNum {
|
||
let totalPages = numberOfPages()
|
||
return totalPages > 0 ? totalPages - 1 : nil
|
||
}
|
||
if isDualPage, let coverIndex = coverPageIndex {
|
||
if pageNum == RDReaderView.blankPageNum {
|
||
return coverIndex
|
||
}
|
||
if pageNum == coverIndex + 1 {
|
||
return RDReaderView.blankPageNum
|
||
}
|
||
}
|
||
let prev = pageNum - 1
|
||
return prev >= 0 ? prev : nil
|
||
}
|
||
|
||
/// UIPageViewController 数据源:返回当前页之前(左/上)的页面控制器
|
||
/// RTL 模式下 before/after 语义互换:before(向右翻)= 下一页
|
||
public func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
|
||
guard let vc = viewController as? RDReaderPageChildViewController else { return nil }
|
||
let isDualPage = landscapeDualPageEnabled && isLandscape
|
||
let isRTL = pageDirection == .rightToLeft
|
||
|
||
let targetNum = isRTL
|
||
? nextPageNum(after: vc.pageNum, isDualPage: isDualPage)
|
||
: prevPageNum(before: vc.pageNum, isDualPage: isDualPage)
|
||
|
||
guard let num = targetNum else { return nil }
|
||
let targetVC = makeSinglePageChildVC(for: num)
|
||
willPreviousTransitionToViewController = targetVC
|
||
return targetVC
|
||
}
|
||
|
||
/// UIPageViewController 数据源:返回当前页之后(右/下)的页面控制器
|
||
/// RTL 模式下 before/after 语义互换
|
||
public func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
|
||
guard let vc = viewController as? RDReaderPageChildViewController else { return nil }
|
||
let isDualPage = landscapeDualPageEnabled && isLandscape
|
||
let isRTL = pageDirection == .rightToLeft
|
||
|
||
let targetNum = isRTL
|
||
? prevPageNum(before: vc.pageNum, isDualPage: isDualPage)
|
||
: nextPageNum(after: vc.pageNum, isDualPage: isDualPage)
|
||
|
||
guard let num = targetNum else { return nil }
|
||
let targetVC = makeSinglePageChildVC(for: num)
|
||
willNextTransitionToViewController = targetVC
|
||
return targetVC
|
||
}
|
||
|
||
/// UIPageViewController 代理:翻页动画完成回调
|
||
/// 更新当前页码,触发预加载,并检测 PageViewController 异常状态
|
||
public func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
|
||
if completed, let firstVC = pageViewController.viewControllers?.first as? RDReaderPageChildViewController {
|
||
let pn = firstVC.pageNum
|
||
if pn != RDReaderView.blankPageNum && pn != RDReaderView.blankEndPageNum {
|
||
currentPage = pn
|
||
primePageCache(around: pn, preferredForward: predictedPageDirection)
|
||
}
|
||
}
|
||
|
||
predictedPageDirection = nil
|
||
finishPageCurlTransition()
|
||
}
|
||
|
||
/// UIPageViewController 代理:即将开始转场动画
|
||
/// 记录预测的翻页方向,用于优化预加载策略
|
||
public func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) {
|
||
pagingController.isTransitioning = true
|
||
willTransitionToViewController = pendingViewControllers.first
|
||
if let target = pendingViewControllers.first as? RDReaderPageChildViewController,
|
||
target.pageNum != RDReaderView.blankPageNum,
|
||
target.pageNum != RDReaderView.blankEndPageNum {
|
||
predictedPageDirection = target.pageNum >= currentPage
|
||
primePageCache(around: target.pageNum, preferredForward: predictedPageDirection)
|
||
}
|
||
}
|
||
}
|