ReadViewSDK/Sources/RDReaderView/ReaderView/RDReaderView+PageCurl.swift
shenlei d15f20b097 feat: 交互协调器拆分、附件提示、暗色图片适配、选区放大镜及文档清理
- 拆分 ContentDelegates/TextContentView 为独立协调器(InteractionCoordinator、LocationResolution、ExternalLinks、AttachmentTooltip)
- 新增 RDEPUBAttachmentTooltipView/OverlayView 附件气泡提示
- 新增 RDEPUBDarkImageAdjuster 暗色模式图片亮度适配
- 新增 RDEPUBSelectionLoupeView 选区放大镜
- 新增 MetadataParseWorker/CancellationController 元数据解析取消机制
- 重构 PresentationRuntime/PaginationCoordinator 精简职责
- 优化 ChapterLoader/WarmupOrchestrator 异步章节加载
- CFI 模块微调与 NoteModels 更新
- 清理冗余文档,更新架构/UML/业务逻辑文档

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-24 17:47:24 +08:00

136 lines
5.6 KiB
Swift

import UIKit
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
}
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
}
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
}
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
}
public func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
let resolvedPage = (pageViewController.viewControllers?.first as? RDReaderPageChildViewController)?.pageNum ?? -1
RDEPUBBackgroundTrace.log(
"PageCurl",
"didFinishAnimating finished=\(finished) completed=\(completed) resolvedPage=\(resolvedPage + 1) currentPageBeforeFinish=\(currentPage + 1)"
)
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()
}
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 {
RDEPUBBackgroundTrace.log(
"PageCurl",
"willTransitionTo targetPage=\(target.pageNum + 1) currentPage=\(currentPage + 1)"
)
predictedPageDirection = target.pageNum >= currentPage
primePageCache(around: target.pageNum, preferredForward: predictedPageDirection)
} else {
RDEPUBBackgroundTrace.log(
"PageCurl",
"willTransitionTo blank target currentPage=\(currentPage + 1)"
)
}
}
}