feat(epub): complete wxread parity scope
This commit is contained in:
@@ -287,6 +287,13 @@ public class RDReaderView: UIView {
|
||||
}
|
||||
}
|
||||
|
||||
/// 将页码钳制到当前书籍的合法范围内
|
||||
private func clampedPageNumber(_ pageNum: Int) -> Int? {
|
||||
let totalPages = dataSource?.pageCountOfReaderView(readerView: self) ?? 0
|
||||
guard totalPages > 0 else { return nil }
|
||||
return min(max(pageNum, 0), totalPages - 1)
|
||||
}
|
||||
|
||||
/// 上一次检测到的横竖屏状态,用于在 layoutSubviews 中检测方向变化
|
||||
private var previousIsLandscape: Bool?
|
||||
|
||||
@@ -339,6 +346,14 @@ public class RDReaderView: UIView {
|
||||
let boundsSize: CGSize
|
||||
}
|
||||
|
||||
/// 当 pageCurl 正在转场时,后续跳转请求会先排队,待当前动画稳定后再执行。
|
||||
private struct PageTransitionRequest: Equatable {
|
||||
let pageNum: Int
|
||||
let animated: Bool
|
||||
}
|
||||
|
||||
private var pendingTransitionRequest: PageTransitionRequest?
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
}
|
||||
@@ -465,12 +480,41 @@ public class RDReaderView: UIView {
|
||||
guard currentPage >= 0 else { return }
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self else { return }
|
||||
self.isTransitioning = false
|
||||
self.pendingTransitionRequest = nil
|
||||
self.willPreviousTransitionToViewController = nil
|
||||
self.willNextTransitionToViewController = nil
|
||||
self.willTransitionToViewController = nil
|
||||
self.invalidatePageCaches()
|
||||
self.rebuildPageViewController()
|
||||
self.transitionToPage(pageNum: self.currentPage, animated: false)
|
||||
}
|
||||
}
|
||||
|
||||
/// pageCurl 动画过程中如果收到新的跳转请求,则排队等待当前动画结束。
|
||||
private func shouldQueuePageTransition(_ request: PageTransitionRequest) -> Bool {
|
||||
guard currentDisplayType == .pageCurl, isTransitioning else { return false }
|
||||
pendingTransitionRequest = request
|
||||
return true
|
||||
}
|
||||
|
||||
/// 收尾 pageCurl 转场,并尝试执行排队中的后续跳转。
|
||||
private func finishPageCurlTransition(repairFaultIfNeeded: Bool = true) {
|
||||
isTransitioning = false
|
||||
willPreviousTransitionToViewController = nil
|
||||
willNextTransitionToViewController = nil
|
||||
willTransitionToViewController = nil
|
||||
|
||||
if repairFaultIfNeeded, detectPageViewControllerFault(pageViewController) {
|
||||
patchPageViewControllerFault()
|
||||
return
|
||||
}
|
||||
|
||||
guard let pendingTransitionRequest else { return }
|
||||
self.pendingTransitionRequest = nil
|
||||
transitionToPage(pageNum: pendingTransitionRequest.pageNum, animated: pendingTransitionRequest.animated)
|
||||
}
|
||||
|
||||
// MARK: - Preload / Forecast
|
||||
|
||||
/// 确保预加载宿主视图已添加到视图层级
|
||||
@@ -706,6 +750,10 @@ public class RDReaderView: UIView {
|
||||
if didAddToParent {
|
||||
pageViewController.didMove(toParent: parentViewController)
|
||||
}
|
||||
|
||||
if currentDisplayType == .pageCurl, !isTransitioning, pendingTransitionRequest != nil {
|
||||
finishPageCurlTransition(repairFaultIfNeeded: false)
|
||||
}
|
||||
}
|
||||
|
||||
/// 从父控制器和视图层级中移除 pageViewController
|
||||
@@ -900,45 +948,65 @@ public class RDReaderView: UIView {
|
||||
/// - pageNum: 目标页码(item 索引)
|
||||
/// - animated: 是否动画过渡
|
||||
public func transitionToPage(pageNum: Int, animated: Bool = false) {
|
||||
guard let safePageNum = clampedPageNumber(pageNum) else { return }
|
||||
switch currentDisplayType {
|
||||
case .pageCurl:
|
||||
let request = PageTransitionRequest(pageNum: safePageNum, animated: animated)
|
||||
if shouldQueuePageTransition(request) {
|
||||
return
|
||||
}
|
||||
|
||||
let isDualPage = landscapeDualPageEnabled && isLandscape
|
||||
// RTL 时动画方向需要反转
|
||||
let direction: UIPageViewController.NavigationDirection
|
||||
if pageDirection == .rightToLeft {
|
||||
direction = pageNum > currentPage ? .reverse : .forward
|
||||
direction = safePageNum > currentPage ? .reverse : .forward
|
||||
} else {
|
||||
direction = pageNum > currentPage ? .forward : .reverse
|
||||
direction = safePageNum > currentPage ? .forward : .reverse
|
||||
}
|
||||
predictedPageDirection = currentPage >= 0 ? safePageNum >= currentPage : nil
|
||||
attachPageViewControllerIfNeeded()
|
||||
if isDualPage {
|
||||
let pair = dualPagePair(for: pageNum)
|
||||
let pair = dualPagePair(for: safePageNum)
|
||||
let leftContent = pageViewForDisplay(pageNum: pair.left)
|
||||
let leftVC = RDReaderPageChildViewController(contentView: leftContent, pageNum: pair.left)
|
||||
isTransitioning = animated
|
||||
if let rightPage = pair.right {
|
||||
let rightContent = pageViewForDisplay(pageNum: rightPage)
|
||||
let rightVC = RDReaderPageChildViewController(contentView: rightContent, pageNum: rightPage)
|
||||
pageViewController.setViewControllers([leftVC, rightVC], direction: animated ? direction : .forward, animated: animated, completion: nil)
|
||||
pageViewController.setViewControllers([leftVC, rightVC], direction: animated ? direction : .forward, animated: animated) { [weak self] _ in
|
||||
guard let self else { return }
|
||||
self.finishPageCurlTransition()
|
||||
}
|
||||
} else {
|
||||
// 封面页独占或奇数最后一页:右侧放空白页
|
||||
let blankNum = isFullScreenPage(pair.left) ? RDReaderView.blankPageNum : RDReaderView.blankEndPageNum
|
||||
let emptyVC = RDReaderPageChildViewController(contentView: UIView(), pageNum: blankNum)
|
||||
pageViewController.setViewControllers([leftVC, emptyVC], direction: animated ? direction : .forward, animated: animated, completion: nil)
|
||||
pageViewController.setViewControllers([leftVC, emptyVC], direction: animated ? direction : .forward, animated: animated) { [weak self] _ in
|
||||
guard let self else { return }
|
||||
self.finishPageCurlTransition()
|
||||
}
|
||||
}
|
||||
currentPage = pair.left
|
||||
primePageCache(around: pair.left, preferredForward: predictedPageDirection)
|
||||
} else {
|
||||
let contentView = pageViewForDisplay(pageNum: pageNum)
|
||||
let vc = RDReaderPageChildViewController(contentView: contentView, pageNum: pageNum)
|
||||
pageViewController.setViewControllers([vc], direction: animated ? direction : .forward, animated: animated, completion: nil)
|
||||
currentPage = pageNum
|
||||
primePageCache(around: pageNum, preferredForward: predictedPageDirection)
|
||||
let contentView = pageViewForDisplay(pageNum: safePageNum)
|
||||
let vc = RDReaderPageChildViewController(contentView: contentView, pageNum: safePageNum)
|
||||
isTransitioning = animated
|
||||
pageViewController.setViewControllers([vc], direction: animated ? direction : .forward, animated: animated) { [weak self] _ in
|
||||
guard let self else { return }
|
||||
self.finishPageCurlTransition()
|
||||
}
|
||||
currentPage = safePageNum
|
||||
primePageCache(around: safePageNum, preferredForward: predictedPageDirection)
|
||||
}
|
||||
default:
|
||||
collectionView.reloadData()
|
||||
collectionView.layoutIfNeeded()
|
||||
collectionView.setContentOffset(layout.currentContentOffset(count: pageNum), animated: animated)
|
||||
currentPage = pageNum
|
||||
primePageCache(around: pageNum, preferredForward: predictedPageDirection)
|
||||
predictedPageDirection = currentPage >= 0 ? safePageNum >= currentPage : nil
|
||||
collectionView.setContentOffset(layout.currentContentOffset(count: safePageNum), animated: animated)
|
||||
currentPage = safePageNum
|
||||
primePageCache(around: safePageNum, preferredForward: predictedPageDirection)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1091,15 +1159,13 @@ extension RDReaderView: UIPageViewControllerDataSource, UIPageViewControllerDele
|
||||
}
|
||||
|
||||
predictedPageDirection = nil
|
||||
|
||||
if detectPageViewControllerFault(pageViewController) {
|
||||
patchPageViewControllerFault()
|
||||
}
|
||||
finishPageCurlTransition()
|
||||
}
|
||||
|
||||
/// UIPageViewController 代理:即将开始转场动画
|
||||
/// 记录预测的翻页方向,用于优化预加载策略
|
||||
public func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) {
|
||||
isTransitioning = true
|
||||
willTransitionToViewController = pendingViewControllers.first
|
||||
if let target = pendingViewControllers.first as? RDReaderPageChildViewController,
|
||||
target.pageNum != RDReaderView.blankPageNum,
|
||||
@@ -1151,6 +1217,9 @@ extension RDReaderView: UICollectionViewDataSource, RDReaderFlowLayoutDelegate,
|
||||
|
||||
/// 布局代理回调:当前可见页码变化时通知
|
||||
public func pageNum(flowLayout: RDReaderFlowLayout, pageIndex: Int) {
|
||||
if currentPage >= 0, currentPage != pageIndex {
|
||||
predictedPageDirection = pageIndex >= currentPage
|
||||
}
|
||||
currentPage = pageIndex
|
||||
primePageCache(around: pageIndex, preferredForward: predictedPageDirection)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user