- Rename source module from RDReaderView to RDEpubReaderView - Move all source files from Sources/RDReaderView/ to Sources/RDEpubReaderView/ - Update podspec: RDReaderView.podspec -> RDEpubReaderView.podspec - Update Podfile, demo project, and CocoaPods config for new pod name - Delete old RDReaderView pod support files from ReadViewDemo/Pods - Add new RDEpubReaderView pod support files - Update documentation (API ref, architecture, UML, conventions, etc.) - Add FixedLayoutRotationTests - Update .gitignore: exclude .DS_Store, manual unpack backups, _ssoft-output
732 lines
23 KiB
Markdown
732 lines
23 KiB
Markdown
# EPUBUI 模块代码级参考文档
|
||
|
||
> 最后更新:2026-06-18
|
||
|
||
---
|
||
|
||
## 1. 模块概述
|
||
|
||
`EPUBUI` 是 ReadViewSDK 的**用户界面层**,位于架构最顶层。它包含阅读器控制器、协调器模式、章节运行时系统、设置面板、文本页面渲染和标注管理等子系统。
|
||
|
||
**文件清单(~60 个 Swift 文件):**
|
||
|
||
| 子系统 | 目录 | 核心文件 | 职责 |
|
||
|--------|------|----------|------|
|
||
| **阅读器控制器** | `EPUBUI/` | `RDEPUBReaderController*.swift` | 主控制器及其扩展 |
|
||
| **协调器** | `ReaderController/` | `RDEPUBReader*Coordinator.swift` | 各功能域协调器 |
|
||
| **运行时** | `ReaderController/` | `RDEPUBReaderRuntime.swift`, `RDEPUBReaderContext.swift` | 运行时状态与依赖 |
|
||
| **章节运行时** | `ReaderController/ChapterRuntime/` | `RDEPUBChapter*.swift` | 按需加载、缓存、页图 |
|
||
| **设置** | `Settings/` | `RDEPUBReaderSettings*.swift` | 配置、主题、设置面板 |
|
||
| **文本页面** | `TextPage/` | `RDEPUBTextContentView*.swift` | 原生文本渲染页面 |
|
||
| **UI 组件** | `EPUBUI/` | `RDEPUBReader*ToolView.swift` | 工具栏、搜索栏、目录 |
|
||
| **笔记弹层** | `Notes/` | `RDEPUBNotePopup*.swift` | 脚注弹层 |
|
||
| **WebView** | `EPUBUI/` | `RDEPUBWebContentView.swift` | WebView 内容页面 |
|
||
|
||
---
|
||
|
||
## 2. 阅读器控制器
|
||
|
||
### 2.1 RDEPUBReaderController
|
||
|
||
**文件:** `RDEPUBReaderController.swift` + 扩展文件
|
||
|
||
主控制器,`UIViewController` 子类,是整个阅读器的入口。
|
||
|
||
```swift
|
||
public final class RDEPUBReaderController: UIViewController {
|
||
public weak var delegate: RDEPUBReaderDelegate?
|
||
public var configuration: RDEPUBReaderConfiguration // 配置(变化时自动重新分页/刷新)
|
||
public var currentLocation: RDEPUBLocation? // 当前阅读位置
|
||
public var currentPageNumber: Int? // 当前页码(1-based)
|
||
public var currentSelection: RDEPUBSelection? // 当前选中文本
|
||
public var highlights: [RDEPUBHighlight] // 高亮列表
|
||
public var bookmarks: [RDEPUBBookmark] // 书签列表
|
||
public var annotations: [RDEPUBAnnotation] // 标注列表(高亮+书签,按时间排序)
|
||
public var tableOfContents: [EPUBTableOfContentsItem] // 目录树
|
||
public var flattenedTableOfContents: [RDEPUBReaderTableOfContentsItem] // 扁平化目录
|
||
|
||
let epubURL: URL // EPUB 文件路径
|
||
let persistence: RDEPUBReaderPersistence? // 持久化代理
|
||
let dependencies: RDEPUBReaderDependencies // 依赖注入
|
||
let readerView = RDEpubReaderView() // 翻页容器
|
||
}
|
||
```
|
||
|
||
**扩展文件职责:**
|
||
|
||
| 文件 | 职责 |
|
||
|------|------|
|
||
| `RDEPUBReaderController+PublicAPI.swift` | 公开 API(跳转、搜索、标注、书签) |
|
||
| `RDEPUBReaderController+DataSource.swift` | `RDEpubReaderPageProvider` 实现 |
|
||
| `RDEPUBReaderController+ContentDelegates.swift` | WebView/TextContentView 代理路由 |
|
||
| `RDEPUBReaderController+LocationResolution.swift` | 页码/位置解析、阅读状态同步 |
|
||
| `RDEPUBReaderController+ExternalLinks.swift` | 外部链接处理(白名单、确认弹窗) |
|
||
| `RDEPUBReaderController+AttachmentTooltip.swift` | 附件 alt 文本 tooltip 展示 |
|
||
| `RDEPUBReaderController+RenderSupport.swift` | 渲染辅助(WebView/TextContent 创建) |
|
||
| `RDEPUBReaderController+RuntimeBridge.swift` | Runtime 桥接 |
|
||
| `RDEPUBReaderController+TableOfContents.swift` | 目录处理 |
|
||
|
||
### 2.2 RDEPUBReaderDelegate
|
||
|
||
**文件:** `RDEPUBReaderDelegate.swift`
|
||
|
||
```swift
|
||
public protocol RDEPUBReaderDelegate: AnyObject {
|
||
func epubReader(_ reader: UIViewController, didOpen publication: RDEPUBPublication)
|
||
func epubReader(_ reader: UIViewController, didUpdateLocation location: RDEPUBLocation)
|
||
func epubReaderDidReachEnd(_ reader: UIViewController)
|
||
func epubReader(_ reader: UIViewController, didChangeSelection selection: RDEPUBSelection?)
|
||
func epubReader(_ reader: UIViewController, didUpdateHighlights highlights: [RDEPUBHighlight])
|
||
func epubReader(_ reader: UIViewController, didUpdateBookmarks bookmarks: [RDEPUBBookmark])
|
||
func epubReader(_ reader: UIViewController, didUpdateSearchResult result: RDEPUBSearchResult?)
|
||
func epubReader(_ reader: UIViewController, didChangeCurrentSearchMatch match: RDEPUBSearchMatch?)
|
||
func epubReader(_ reader: UIViewController, didUpdateCurrentTableOfContentsItem item: RDEPUBReaderTableOfContentsItem?)
|
||
func epubReader(_ reader: UIViewController, didActivateExternalLink url: URL)
|
||
func epubReader(_ reader: UIViewController, shouldOpenExternalURL url: URL) -> Bool
|
||
func epubReader(_ reader: UIViewController, didFailWithError error: Error)
|
||
func epubReader(_ reader: UIViewController, configureTopToolView topToolView: RDEPUBReaderTopToolView)
|
||
}
|
||
```
|
||
|
||
所有方法均有默认空实现。
|
||
|
||
### 2.3 RDEPUBReaderPersistence
|
||
|
||
**文件:** `RDEPUBReaderPersistence.swift`
|
||
|
||
持久化协议,由宿主 App 实现。
|
||
|
||
```swift
|
||
public protocol RDEPUBReaderPersistence: AnyObject {
|
||
func loadLocation(for bookIdentifier: String) -> RDEPUBLocation?
|
||
func saveLocation(_ location: RDEPUBLocation, for bookIdentifier: String)
|
||
func loadBookmarks(for bookIdentifier: String) -> [RDEPUBBookmark]
|
||
func saveBookmarks(_ bookmarks: [RDEPUBBookmark], for bookIdentifier: String)
|
||
func loadHighlights(for bookIdentifier: String) -> [RDEPUBHighlight]
|
||
func saveHighlights(_ highlights: [RDEPUBHighlight], for bookIdentifier: String)
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 运行时与上下文
|
||
|
||
### 3.1 RDEPUBReaderContext
|
||
|
||
**文件:** `ReaderController/RDEPUBReaderContext.swift`
|
||
|
||
阅读器的共享上下文,持有所有运行时状态。协调器通过 `unowned` 引用访问。
|
||
|
||
```swift
|
||
final class RDEPUBReaderContext {
|
||
weak var controller: RDEPUBReaderController?
|
||
weak var readerView: RDEpubReaderView?
|
||
var dependencies: RDEPUBReaderDependencies
|
||
var runtime: RDEPUBReaderRuntime?
|
||
|
||
// 解析状态
|
||
var parser: RDEPUBParser?
|
||
var publication: RDEPUBPublication?
|
||
var readingSession: RDEPUBReadingSession?
|
||
var textBook: RDEPUBTextBook?
|
||
var bookPageMap: RDEPUBBookPageMap?
|
||
|
||
// 标注状态
|
||
var activeBookmarks: [RDEPUBBookmark]
|
||
var activeHighlights: [RDEPUBHighlight]
|
||
var currentBookIdentifier: String?
|
||
var selectionState: RDEPUBSelectionState
|
||
var currentSelection: RDEPUBSelection?
|
||
|
||
// 搜索状态
|
||
var searchState: RDEPUBSearchState?
|
||
}
|
||
```
|
||
|
||
### 3.2 RDEPUBReaderDependencies
|
||
|
||
**文件:** `ReaderController/RDEPUBReaderDependencies.swift`
|
||
|
||
依赖注入容器,支持测试替身。
|
||
|
||
```swift
|
||
public struct RDEPUBReaderDependencies {
|
||
public var environment: any RDEPUBReaderDisplayEnvironment
|
||
public var makeParser: () -> RDEPUBParser
|
||
public var makePaginator: () -> RDEPUBPaginator
|
||
public var makeTextBookBuilder: (RDEPUBTextRenderer, RDEPUBTextBookCache?, RDEPUBTextLayoutConfig) -> RDEPUBTextBookBuilder
|
||
public var makePlainTextBookBuilder: (RDEPUBTextRenderer, RDEPUBTextLayoutConfig) -> RDEpubPlainTextBookBuilder
|
||
public var makeTextRenderer: (RDEPUBTextRenderingEngine) -> RDEPUBTextRenderer
|
||
|
||
public static var live: RDEPUBReaderDependencies // 默认实现
|
||
}
|
||
```
|
||
|
||
### 3.3 RDEPUBReaderRuntime
|
||
|
||
**文件:** `ReaderController/RDEPUBReaderRuntime.swift`
|
||
|
||
运行时管理器,持有所有协调器和子系统。
|
||
|
||
```swift
|
||
final class RDEPUBReaderRuntime {
|
||
lazy var chapterRuntimeStore = RDEPUBChapterRuntimeStore()
|
||
lazy var summaryDiskCache: RDEPUBChapterSummaryDiskCache
|
||
lazy var chapterLoader: RDEPUBChapterLoader
|
||
lazy var pageResolver: RDEPUBPageResolver
|
||
lazy var loadCoordinator: RDEPUBReaderLoadCoordinator
|
||
lazy var paginationCoordinator: RDEPUBReaderPaginationCoordinator
|
||
lazy var locationCoordinator: RDEPUBReaderLocationCoordinator
|
||
lazy var searchCoordinator: RDEPUBReaderSearchCoordinator
|
||
lazy var chromeCoordinator: RDEPUBReaderChromeCoordinator
|
||
lazy var annotationCoordinator: RDEPUBReaderAnnotationCoordinator
|
||
lazy var viewportMonitor: RDEPUBReaderViewportMonitor
|
||
lazy var jumpSessionManager: RDEPUBJumpSessionManager
|
||
lazy var backgroundPriorityManager: RDEPUBBackgroundPriorityManager
|
||
lazy var backgroundCoverageStore: RDEPUBBackgroundCoverageStore
|
||
lazy var reconciliationCoordinator: RDEPUBPageMapReconciliationCoordinator
|
||
|
||
var isSettingsPanelOpen: Bool
|
||
var needsFullRepaginationAfterSettingsClose: Bool
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 协调器子系统
|
||
|
||
采用 **Coordinator 模式**,每个功能域由独立的协调器管理。
|
||
|
||
### 4.1 RDEPUBReaderLoadCoordinator
|
||
|
||
**文件:** `ReaderController/RDEPUBReaderLoadCoordinator.swift`
|
||
|
||
负责初始加载流程:解析 EPUB → 创建 Publication → 恢复阅读位置。
|
||
|
||
```swift
|
||
final class RDEPUBReaderLoadCoordinator {
|
||
func startInitialLoadIfNeeded() // 开始初始加载
|
||
func loadPublication() // 解析 EPUB 文件
|
||
func applyParsedPublication(...) // 应用解析结果
|
||
}
|
||
```
|
||
|
||
### 4.2 RDEPUBReaderPaginationCoordinator
|
||
|
||
**文件:** `ReaderController/RDEPUBReaderPaginationCoordinator.swift`
|
||
|
||
负责分页调度:WebView 分页 → 文本构建 → 页图生成。
|
||
|
||
```swift
|
||
final class RDEPUBReaderPaginationCoordinator {
|
||
func startPagination(...) // 开始分页
|
||
func applyPageCounts(...) // 应用页数结果
|
||
func repaginatePreservingCurrentLocation() // 重新分页(保持位置)
|
||
}
|
||
```
|
||
|
||
### 4.3 RDEPUBReaderLocationCoordinator
|
||
|
||
**文件:** `ReaderController/RDEPUBReaderLocationCoordinator.swift`
|
||
|
||
负责位置管理:恢复位置、记录位置变化、目录跳转。
|
||
|
||
```swift
|
||
final class RDEPUBReaderLocationCoordinator {
|
||
func restoreReadingLocation(_ location: RDEPUBLocation, animated: Bool, ...) -> Bool
|
||
func currentVisibleLocation() -> RDEPUBLocation?
|
||
func recordPageChangeIfNeeded()
|
||
}
|
||
```
|
||
|
||
### 4.4 RDEPUBReaderSearchCoordinator
|
||
|
||
**文件:** `ReaderController/RDEPUBReaderSearchCoordinator.swift`
|
||
|
||
负责搜索管理:执行搜索、导航到匹配项、清除搜索。
|
||
|
||
```swift
|
||
final class RDEPUBReaderSearchCoordinator {
|
||
func search(keyword: String)
|
||
func searchNext() -> Bool
|
||
func searchPrevious() -> Bool
|
||
func selectSearchMatch(at index: Int) -> Bool
|
||
func clearSearch()
|
||
}
|
||
```
|
||
|
||
### 4.5 RDEPUBReaderChromeCoordinator
|
||
|
||
**文件:** `ReaderController/RDEPUBReaderChromeCoordinator.swift`
|
||
|
||
负责 UI Chrome(工具栏、搜索栏)的创建和状态更新。
|
||
|
||
```swift
|
||
final class RDEPUBReaderChromeCoordinator {
|
||
func makeTopToolView() -> RDEPUBReaderTopToolView
|
||
func makeBottomToolView() -> RDEPUBReaderBottomToolView
|
||
func updateReaderChrome()
|
||
func toggleSearchBar()
|
||
func presentTableOfContents()
|
||
func presentSettings()
|
||
}
|
||
```
|
||
|
||
### 4.6 RDEPUBReaderAnnotationCoordinator
|
||
|
||
**文件:** `ReaderController/RDEPUBReaderAnnotationCoordinator.swift`
|
||
|
||
负责标注管理:高亮、书签的增删改查。
|
||
|
||
```swift
|
||
final class RDEPUBReaderAnnotationCoordinator {
|
||
func addHighlight(from selection: RDEPUBSelection?, color: String, note: String?) -> RDEPUBHighlight?
|
||
func removeHighlight(withID id: String)
|
||
func addBookmark(for location: RDEPUBLocation, ...) -> RDEPUBBookmark?
|
||
func removeBookmark(withID id: String)
|
||
func toggleBookmark() -> Bool
|
||
func updateCurrentSelection(_ selection: RDEPUBSelection?)
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 章节运行时子系统
|
||
|
||
**目录:** `ReaderController/ChapterRuntime/`
|
||
|
||
按需加载章节、管理章节缓存、维护全书页图。
|
||
|
||
### 5.1 RDEPUBChapterRuntimeStore
|
||
|
||
**文件:** `ChapterRuntime/RDEPUBChapterRuntimeStore.swift`
|
||
|
||
章节数据的核心存储,管理内存缓存和窗口。
|
||
|
||
```swift
|
||
final class RDEPUBChapterRuntimeStore {
|
||
let chapterLoadQueue: DispatchQueue // 后台加载队列
|
||
private(set) var currentSpineIndex: Int?
|
||
private(set) var windowSpineIndices: [Int] // 当前窗口内的 spine 索引
|
||
|
||
func chapterData(for spineIndex: Int) -> RDEPUBRuntimeChapter?
|
||
func insertChapter(_ chapter: RDEPUBRuntimeChapter)
|
||
func setCurrentChapter(spineIndex: Int, totalSpineCount: Int, windowRadius: Int)
|
||
func evictableSpineIndices() -> [Int]
|
||
func evict(spineIndex: Int)
|
||
}
|
||
```
|
||
|
||
### 5.2 RDEPUBChapterLoader
|
||
|
||
**文件:** `ChapterRuntime/RDEPUBChapterLoader.swift`
|
||
|
||
章节按需加载器,支持优先级和磁盘摘要缓存。
|
||
|
||
```swift
|
||
final class RDEPUBChapterLoader {
|
||
enum LoadPriority {
|
||
case navigation // 导航(最高优先级)
|
||
case preview // 预览
|
||
case prefetch // 预取(最低优先级)
|
||
}
|
||
|
||
func loadChapter(
|
||
spineIndex: Int,
|
||
store: RDEPUBChapterRuntimeStore,
|
||
priority: LoadPriority,
|
||
completion: @escaping (Result<RDEPUBRuntimeChapter, Error>) -> Void
|
||
)
|
||
}
|
||
```
|
||
|
||
**加载流程:**
|
||
1. 检查内存缓存(`RDEPUBChapterDataCache`)
|
||
2. 检查页数缓存(`RDEPUBPageCountCache`)
|
||
3. 检查磁盘摘要缓存(`RDEPUBChapterSummaryDiskCache`)
|
||
4. 构建章节(排版 + 分页)
|
||
5. 写入缓存
|
||
|
||
### 5.3 RDEPUBChapterWindowCoordinator
|
||
|
||
**文件:** `ChapterRuntime/RDEPUBChapterWindowCoordinator.swift`
|
||
|
||
管理章节窗口(当前章 + 前后各 N 章),协调加载和驱逐。
|
||
|
||
```swift
|
||
final class RDEPUBChapterWindowCoordinator {
|
||
private(set) var currentSnapshot: RDEPUBChapterWindowSnapshot?
|
||
var onSnapshotChanged: ((RDEPUBChapterWindowSnapshot) -> Void)?
|
||
|
||
func openBook(at targetSpineIndex: Int, restoreChapterOffset: Int?)
|
||
func navigateToChapter(at spineIndex: Int)
|
||
}
|
||
```
|
||
|
||
### 5.4 RDEPUBBookPageMap
|
||
|
||
**文件:** `ChapterRuntime/RDEPUBBookPageMap.swift`
|
||
|
||
全书页图,映射绝对页码 ↔ spine 索引 + 本地页码。
|
||
|
||
```swift
|
||
struct RDEPUBBookPageMap {
|
||
let entries: [RDEPUBBookPageMapEntry]
|
||
let totalPages: Int
|
||
|
||
func absolutePageIndex(spineIndex: Int, localPageIndex: Int) -> Int?
|
||
func spineIndex(forAbsolutePage absolutePage: Int) -> Int?
|
||
func localPageIndex(forAbsolutePage absolutePage: Int) -> Int?
|
||
func chapterIndex(forSpineIndex spineIndex: Int) -> Int?
|
||
}
|
||
```
|
||
|
||
### 5.5 RDEPUBPageResolver
|
||
|
||
**文件:** `ChapterRuntime/RDEPUBPageResolver.swift`
|
||
|
||
将绝对页码解析为具体的页面数据。
|
||
|
||
```swift
|
||
final class RDEPUBPageResolver {
|
||
func resolvePage(absolutePageIndex: Int) -> RDEPUBResolvedPage?
|
||
}
|
||
|
||
struct RDEPUBResolvedPage {
|
||
let page: RDEPUBTextPage
|
||
let chapter: RDEPUBRuntimeChapter
|
||
let chapterIndex: Int
|
||
}
|
||
```
|
||
|
||
### 5.6 其他 ChapterRuntime 组件
|
||
|
||
| 文件 | 职责 |
|
||
|------|------|
|
||
| `RDEPUBRuntimeChapter.swift` | 运行时章节模型(包含分页后的页面列表) |
|
||
| `RDEPUBRuntimePageCount.swift` | 页数缓存模型 |
|
||
| `RDEPUBChapterDataCache.swift` | 章节数据内存缓存(NSCache) |
|
||
| `RDEPUBPageCountCache.swift` | 页数缓存 |
|
||
| `RDEPUBChapterCacheKey.swift` | 缓存键(pageSize + fontSize + lineHeight) |
|
||
| `RDEPUBChapterSummaryDiskCache.swift` | 章节摘要磁盘缓存 |
|
||
| `RDEPUBChapterWindowSnapshot.swift` | 窗口快照(当前可见章节集合) |
|
||
| `RDEPUBChapterLocation.swift` | 章节位置模型 |
|
||
| `RDEPUBChapterOffsetMap.swift` | 章节偏移映射 |
|
||
| `RDEPUBBackgroundTrace.swift` | 后台任务追踪日志 |
|
||
| `RDEPUBMetadataParseWorker.swift` | 后台元数据解析 worker |
|
||
| `RDEPUBMetadataParseCancellationController.swift` | 解析取消控制器 |
|
||
|
||
---
|
||
|
||
## 6. 设置子系统
|
||
|
||
**目录:** `Settings/`
|
||
|
||
### 6.1 RDEPUBReaderConfiguration
|
||
|
||
**文件:** `Settings/RDEPUBReaderConfiguration.swift`
|
||
|
||
阅读器配置模型。
|
||
|
||
```swift
|
||
public struct RDEPUBReaderConfiguration: Equatable {
|
||
public var fontSize: CGFloat
|
||
public var lineHeightMultiple: CGFloat
|
||
public var fontChoice: RDEPUBReaderFontChoice
|
||
public var numberOfColumns: Int
|
||
public var columnGap: CGFloat
|
||
// ... 更多配置项
|
||
}
|
||
|
||
public enum RDEPUBReaderFontChoice: String, Codable, CaseIterable {
|
||
case system // 系统字体
|
||
case serif // 宋体
|
||
case rounded // 圆体
|
||
case monospaced // 等宽
|
||
}
|
||
|
||
public enum RDEPUBTextRenderingEngine: Equatable {
|
||
case dtCoreText
|
||
}
|
||
```
|
||
|
||
### 6.2 RDEPUBReaderSettings
|
||
|
||
**文件:** `Settings/RDEPUBReaderSettings.swift`
|
||
|
||
设置状态管理。
|
||
|
||
### 6.3 RDEPUBReaderSettingsViewController
|
||
|
||
**文件:** `Settings/RDEPUBReaderSettingsViewController.swift`
|
||
|
||
设置面板 VC(字体大小、行高、字体选择、主题等)。
|
||
|
||
### 6.4 RDEPUBReaderTheme
|
||
|
||
**文件:** `Settings/RDEPUBReaderTheme.swift`
|
||
|
||
主题定义(日间/夜间/护眼等)。
|
||
|
||
---
|
||
|
||
## 7. 文本页面子系统
|
||
|
||
**目录:** `TextPage/`
|
||
|
||
原生文本渲染模式(`textReflowable`)的页面视图。
|
||
|
||
### 7.1 RDEPUBTextContentView
|
||
|
||
**文件:** `TextPage/RDEPUBTextContentView.swift`
|
||
|
||
文本内容视图,使用 CoreText 渲染 `NSAttributedString`。
|
||
|
||
```swift
|
||
final class RDEPUBTextContentView: UIView, UIGestureRecognizerDelegate {
|
||
weak var delegate: RDEPUBTextContentViewDelegate?
|
||
|
||
func configure(page: RDEPUBTextPage, ...)
|
||
func applyHighlights(_ highlights: [RDEPUBHighlight])
|
||
func applySearchState(_ state: RDEPUBSearchState?)
|
||
}
|
||
```
|
||
|
||
### 7.2 RDEPUBTextPageRenderView
|
||
|
||
**文件:** `TextPage/RDEPUBTextPageRenderView.swift`
|
||
|
||
CoreText 渲染视图,绘制 `NSAttributedString` 到屏幕上。
|
||
|
||
### 7.3 RDEPUBTextAnnotationOverlay
|
||
|
||
**文件:** `TextPage/RDEPUBTextAnnotationOverlay.swift`
|
||
|
||
标注叠加层,绘制高亮和下划线。
|
||
|
||
### 7.4 RDEPUBSelectionOverlayView
|
||
|
||
**文件:** `TextPage/RDEPUBSelectionOverlayView.swift`
|
||
|
||
文本选择叠加层(选择手柄)。
|
||
|
||
### 7.5 RDEPUBTextSelectionController
|
||
|
||
**文件:** `TextPage/RDEPUBTextSelectionController.swift`
|
||
|
||
文本选择手势控制器。
|
||
|
||
### 7.6 RDEPUBPageInteractionController
|
||
|
||
**文件:** `TextPage/RDEPUBPageInteractionController.swift`
|
||
|
||
页面交互控制器(长按选择、点击标注等)。
|
||
|
||
### 7.7 RDEPUBPageLayoutSnapshot
|
||
|
||
**文件:** `TextPage/RDEPUBPageLayoutSnapshot.swift`
|
||
|
||
页面布局快照(用于选择定位)。
|
||
|
||
### 7.8 RDEPUBTextPageDecorationView
|
||
|
||
**文件:** `TextPage/RDEPUBTextPageDecorationView.swift`
|
||
|
||
页面装饰视图(页码、页眉等)。
|
||
|
||
---
|
||
|
||
## 8. UI 组件
|
||
|
||
### 8.1 工具栏
|
||
|
||
| 文件 | 职责 |
|
||
|------|------|
|
||
| `RDEPUBReaderTopToolView.swift` | 顶部工具栏(返回、搜索、书签) |
|
||
| `RDEPUBReaderBottomToolView.swift` | 底部工具栏(目录、书签、高亮、设置) |
|
||
| `RDEPUBReaderToolView.swift` | 工具栏基类 |
|
||
|
||
### 8.2 搜索栏
|
||
|
||
**文件:** `RDEPUBReaderSearchBarView.swift`
|
||
|
||
搜索输入栏(输入框 + 上一个/下一个 + 关闭)。
|
||
|
||
### 8.3 目录
|
||
|
||
**文件:** `RDEPUBReaderChapterListController.swift`
|
||
|
||
目录列表 VC,支持多级目录展开。
|
||
|
||
**文件:** `RDEPUBReaderTableOfContentsItem.swift`
|
||
|
||
目录项模型。
|
||
|
||
### 8.4 高亮管理
|
||
|
||
**文件:** `RDEPUBReaderHighlightsViewController.swift`
|
||
|
||
高亮列表 VC。
|
||
|
||
### 8.5 笔记弹层
|
||
|
||
**目录:** `Notes/`
|
||
|
||
| 文件 | 职责 |
|
||
|------|------|
|
||
| `RDEPUBNotePopupCoordinator.swift` | 脚注弹层协调器 |
|
||
| `RDEPUBNotePopupViewController.swift` | 脚注弹层 VC |
|
||
|
||
### 8.6 WebView 内容视图
|
||
|
||
**文件:** `RDEPUBWebContentView.swift`
|
||
|
||
WebView 模式的内容页面视图。
|
||
|
||
### 8.7 装饰叠加层
|
||
|
||
**文件:** `RDEPUBWebDecorationOverlayView.swift`
|
||
|
||
WebView 模式的装饰叠加层(高亮、搜索高亮)。
|
||
|
||
---
|
||
|
||
## 9. 状态模型
|
||
|
||
### 9.1 RDEPUBSelectionState
|
||
|
||
```swift
|
||
enum RDEPUBSelectionState: Equatable {
|
||
case idle // 无选择
|
||
case selecting(anchor: Int) // 选择中
|
||
case selected(RDEPUBSelection) // 已选择
|
||
case committingAction(RDEPUBSelection, action: RDEPUBAnnotationMenuAction) // 执行操作中
|
||
}
|
||
```
|
||
|
||
### 9.2 RDEPUBReaderUIState
|
||
|
||
```swift
|
||
struct RDEPUBReaderUIState {
|
||
let canToggleBookmark: Bool
|
||
let hasBookmarkAtCurrentLocation: Bool
|
||
let canShowBookmarks: Bool
|
||
let canAddHighlight: Bool
|
||
let canShowHighlights: Bool
|
||
let showsTableOfContents: Bool
|
||
let allowsHighlights: Bool
|
||
let showsSettingsPanel: Bool
|
||
}
|
||
```
|
||
|
||
### 9.3 RDEPUBViewportTypes
|
||
|
||
**文件:** `RDEPUBViewportTypes.swift`
|
||
|
||
视口相关模型。
|
||
|
||
---
|
||
|
||
## 10. 其他组件
|
||
|
||
### 10.1 RDEPUBReaderViewportMonitor
|
||
|
||
**文件:** `ReaderController/RDEPUBReaderViewportMonitor.swift`
|
||
|
||
视口变化监听器(旋转、尺寸变化)。
|
||
|
||
### 10.2 RDEPUBJumpSession
|
||
|
||
**文件:** `ReaderController/RDEPUBJumpSession.swift`
|
||
|
||
跳转会话管理(远距跳转时的加载状态)。
|
||
|
||
### 10.3 RDEPUBBackgroundPriorityPolicy
|
||
|
||
**文件:** `ReaderController/RDEPUBBackgroundPriorityPolicy.swift`
|
||
|
||
后台加载优先级策略。
|
||
|
||
### 10.4 RDEPUBBackgroundCoverageStore
|
||
|
||
**文件:** `ReaderController/RDEPUBBackgroundCoverageStore.swift`
|
||
|
||
后台加载覆盖范围追踪。
|
||
|
||
### 10.5 RDEPUBPageMapReconciliationCoordinator
|
||
|
||
**文件:** `ReaderController/RDEPUBPageMapReconciliationCoordinator.swift`
|
||
|
||
页图协调器(按需分页与全量分页的结果合并)。
|
||
|
||
### 10.6 RDEpubURLReaderController
|
||
|
||
**文件:** `RDEpubURLReaderController.swift`
|
||
|
||
URL 阅读器控制器(用于打开单个 URL)。
|
||
|
||
### 10.7 UIColor+RDEPUBHex
|
||
|
||
**文件:** `UIColor+RDEPUBHex.swift`
|
||
|
||
UIColor 十六进制扩展。
|
||
|
||
---
|
||
|
||
## 11. 设计模式总结
|
||
|
||
| 模式 | 应用 |
|
||
|------|------|
|
||
| **Coordinator 模式** | 7 个独立协调器分管各功能域 |
|
||
| **Context 模式** | `RDEPUBReaderContext` 共享上下文,避免循环依赖 |
|
||
| **依赖注入** | `RDEPUBReaderDependencies` 工厂方法注入 |
|
||
| **按需加载** | `RDEPUBChapterLoader` 章节级按需加载 |
|
||
| **窗口管理** | `RDEPUBChapterWindowCoordinator` 滑动窗口驱逐 |
|
||
| **快照管理** | `RDEPUBBookPageMap` 全书页图快照 |
|
||
| **状态机** | `RDEPUBSelectionState` 选择状态管理 |
|
||
| **磁盘缓存** | `RDEPUBChapterSummaryDiskCache` 章节摘要持久化 |
|
||
|
||
---
|
||
|
||
## 12. 数据流图
|
||
|
||
```
|
||
用户打开 EPUB
|
||
│
|
||
▼
|
||
RDEPUBReaderController.init(epubURL:)
|
||
│
|
||
▼ viewDidLoad()
|
||
RDEPUBReaderLoadCoordinator.startInitialLoadIfNeeded()
|
||
│
|
||
├── RDEPUBParser.parse(epubURL:) → 解析 EPUB
|
||
├── RDEPUBPublication 创建
|
||
├── 恢复阅读位置(persistence.loadLocation)
|
||
│
|
||
▼
|
||
RDEPUBReaderRuntime.applyParsedPublication()
|
||
│
|
||
├── 根据 readingProfile 选择渲染模式
|
||
│ ├── webInteractive → WebView 分页 → RDEPUBPaginator
|
||
│ └── textReflowable → 文本构建 → RDEPUBTextBookBuilder
|
||
│
|
||
├── RDEPUBChapterWindowCoordinator.openBook()
|
||
│ └── RDEPUBChapterLoader.loadChapter() → 按需加载
|
||
│
|
||
├── RDEPUBBookPageMap 生成
|
||
│
|
||
└── RDEpubReaderView.transitionToPage() → 显示页面
|
||
|
||
用户翻页
|
||
│
|
||
▼
|
||
RDEpubReaderView.currentPage 变化
|
||
│
|
||
├── RDEPUBReaderLocationCoordinator.recordPageChangeIfNeeded()
|
||
│ └── persistence.saveLocation()
|
||
│
|
||
├── RDEPUBChapterWindowCoordinator 检查是否需要加载新章节
|
||
│
|
||
└── RDEPUBReaderChromeCoordinator.updateReaderChrome()
|
||
```
|