源码注释: - 为 ~60 个 Swift 文件补充缺失的 doc comment(file header、类型、属性、方法) - 修正 4 处错误注释:翻页模式数量、搜索行为描述、手势识别器描述、悬空文档块 文档维护: - 删除重复文档:WXRead/读书EPUB阅读器实现架构.md(与微信读书版完全一致) - 合并重叠文档:阅读器规划.md → 阅读器功能开发计划.md(单一真值) - 修正过时内容:所有文档中"四种翻页模式"→"三种",移除 horizontalCoverScroll - 更新架构图:补齐 EPUBUI/ReaderController、Paging/、Typesetter/ 等子目录 - 更新 index.md 索引:新增开发计划和架构对比文档引用
88 lines
3.0 KiB
Swift
88 lines
3.0 KiB
Swift
//
|
||
// RDReaderSpreadResolver.swift
|
||
// ReadViewSDK
|
||
//
|
||
// 文件职责:页面展开(spread)解析器,负责计算双页模式下的页面配对和翻页目标。
|
||
//
|
||
|
||
import Foundation
|
||
|
||
/// 页面展开解析器
|
||
/// 处理横屏双页模式下的页码配对逻辑,包括封面页独占、双页对齐、
|
||
/// 以及相邻页面跳转等计算。
|
||
struct RDReaderSpreadResolver {
|
||
/// 判断指定页码是否为全屏独占页面(如封面页在双页模式下独占一屏)
|
||
func isFullScreenPage(
|
||
_ pageNum: Int,
|
||
landscapeDualPageEnabled: Bool,
|
||
isLandscape: Bool,
|
||
coverPageIndex: Int?
|
||
) -> Bool {
|
||
guard landscapeDualPageEnabled, isLandscape, let coverIndex = coverPageIndex else { return false }
|
||
return pageNum == coverIndex
|
||
}
|
||
|
||
/// 计算指定页码在双页模式下的左右页配对,返回 (左页, 右页?)。
|
||
/// 封面页独占时单独处理,后续页面按两页一组配对。
|
||
func dualPagePair(
|
||
for pageNum: Int,
|
||
totalPages: Int,
|
||
coverPageIndex: Int?
|
||
) -> (left: Int, right: Int?) {
|
||
if let coverIndex = coverPageIndex {
|
||
if pageNum == coverIndex {
|
||
return (coverIndex, nil)
|
||
}
|
||
let adjustedIndex = pageNum - (coverIndex + 1)
|
||
let pairStart = coverIndex + 1 + (adjustedIndex / 2) * 2
|
||
let left = pairStart
|
||
let right = pairStart + 1 < totalPages ? pairStart + 1 : nil
|
||
return (left, right)
|
||
}
|
||
|
||
let left = (pageNum / 2) * 2
|
||
let right = left + 1 < totalPages ? left + 1 : nil
|
||
return (left, right)
|
||
}
|
||
|
||
/// 计算从指定页码出发的下一个(或上一个)双页展开的起始页码
|
||
func adjacentDualPage(
|
||
from pageNum: Int,
|
||
totalPages: Int,
|
||
coverPageIndex: Int?,
|
||
forward: Bool
|
||
) -> Int? {
|
||
let pair = dualPagePair(for: pageNum, totalPages: totalPages, coverPageIndex: coverPageIndex)
|
||
if forward {
|
||
let nextStart = (pair.right ?? pair.left) + 1
|
||
return nextStart < totalPages ? nextStart : nil
|
||
}
|
||
|
||
let prevEnd = pair.left - 1
|
||
guard prevEnd >= 0 else { return nil }
|
||
return dualPagePair(for: prevEnd, totalPages: totalPages, coverPageIndex: coverPageIndex).left
|
||
}
|
||
|
||
/// 计算下一页(或上一页)的页码,自动根据单页/双页模式选择合适的算法
|
||
func nextPage(
|
||
from currentPage: Int,
|
||
totalPages: Int,
|
||
pagesPerScreen: Int,
|
||
coverPageIndex: Int?,
|
||
forward: Bool
|
||
) -> Int? {
|
||
if pagesPerScreen > 1 {
|
||
return adjacentDualPage(
|
||
from: currentPage,
|
||
totalPages: totalPages,
|
||
coverPageIndex: coverPageIndex,
|
||
forward: forward
|
||
)
|
||
}
|
||
|
||
let target = currentPage + (forward ? 1 : -1)
|
||
guard target >= 0, target < totalPages else { return nil }
|
||
return target
|
||
}
|
||
}
|