Files
ReadViewSDK/Sources/RDReaderView/EPUBUI/RDEPUBReaderController+RuntimeBridge.swift
T
shenandshen 948004eed1 docs: 补充注释、修正过时文档、清理重复内容
源码注释:
- 为 ~60 个 Swift 文件补充缺失的 doc comment(file header、类型、属性、方法)
- 修正 4 处错误注释:翻页模式数量、搜索行为描述、手势识别器描述、悬空文档块

文档维护:
- 删除重复文档:WXRead/读书EPUB阅读器实现架构.md(与微信读书版完全一致)
- 合并重叠文档:阅读器规划.md → 阅读器功能开发计划.md(单一真值)
- 修正过时内容:所有文档中"四种翻页模式"→"三种",移除 horizontalCoverScroll
- 更新架构图:补齐 EPUBUI/ReaderController、Paging/、Typesetter/ 等子目录
- 更新 index.md 索引:新增开发计划和架构对比文档引用
2026-06-01 09:33:23 +08:00

285 lines
10 KiB
Swift

// RDEPUBReaderController+RuntimeBridge.swift
// EPUB 阅读器运行时桥接层
// 将阅读器控制器的公开行为委托给 runtime 对象执行,涵盖配置应用、
// 出版物加载与分页、阅读位置恢复、加载状态管理、错误处理等生命周期操作。
import UIKit
/// RDEPUBReaderController 运行时桥接扩展
///
/// 本文件将阅读器控制器的公开行为委托给 runtime 对象执行,涵盖配置应用、
/// 出版物加载与分页、阅读位置恢复、加载状态管理、错误处理等生命周期操作。
extension RDEPUBReaderController {
/// 应用阅读器视图配置,处理显示类型/翻页方向/横屏双页等变更并恢复位置
func applyReaderViewConfiguration() {
let resolvedDirection = resolvedPageDirection()
let presentationDidChange = readerView.currentDisplayType != configuration.displayType
|| readerView.landscapeDualPageEnabled != configuration.landscapeDualPageEnabled
|| readerView.pageDirection != resolvedDirection
let preservedLocation = presentationDidChange
? (runtime.viewportMonitor.consumePendingPresentationRestoreLocation() ?? currentVisibleLocation() ?? persistenceLocation())
: nil
view.backgroundColor = configuration.theme.contentBackgroundColor
readerView.landscapeDualPageEnabled = configuration.landscapeDualPageEnabled
readerView.pageDirection = resolvedDirection
updateReaderChrome()
if presentationDidChange {
readerView.switchReaderDisplayType(configuration.displayType)
if let preservedLocation {
_ = restoreReadingLocation(preservedLocation)
}
}
}
/// 启动初始加载流程(如果尚未加载)
func startInitialLoadIfNeeded() {
runtime.startInitialLoadIfNeeded()
}
/// 加载 EPUB 出版物
func loadPublication() {
runtime.loadPublication()
}
/// 应用已解析的出版物数据(解析器、出版物模型、书签、高亮等)
func applyParsedPublication(
parser: RDEPUBParser,
publication: RDEPUBPublication,
bookIdentifier: String,
restoreLocation: RDEPUBLocation?,
bookmarks: [RDEPUBBookmark],
highlights: [RDEPUBHighlight]
) {
runtime.applyParsedPublication(
parser: parser,
publication: publication,
bookIdentifier: bookIdentifier,
restoreLocation: restoreLocation,
bookmarks: bookmarks,
highlights: highlights
)
}
/// 对出版物执行分页计算
func paginatePublication(restoreLocation: RDEPUBLocation?) {
runtime.paginatePublication(restoreLocation: restoreLocation)
}
/// 应用文本书籍数据并恢复阅读位置
func applyTextBook(_ textBook: RDEPUBTextBook, restoreLocation: RDEPUBLocation?) {
runtime.applyTextBook(textBook, restoreLocation: restoreLocation)
}
/// 应用分页快照(页面列表与章节信息)
func applyPaginationSnapshot(
_ snapshot: (pages: [EPUBPage], chapters: [EPUBChapterInfo]),
restoreLocation: RDEPUBLocation?
) {
runtime.applyPaginationSnapshot(snapshot, restoreLocation: restoreLocation)
}
/// 完成分页流程并恢复阅读位置
func finishPagination(restoreLocation: RDEPUBLocation?) {
runtime.finishPagination(restoreLocation: restoreLocation)
}
/// 保留当前位置重新执行分页
func repaginatePreservingCurrentLocation() {
runtime.repaginatePreservingCurrentLocation()
}
/// 恢复到指定阅读位置,返回是否成功
@discardableResult
func restoreReadingLocation(_ location: RDEPUBLocation, animated: Bool = false) -> Bool {
runtime.restoreReadingLocation(location, animated: animated)
}
/// 获取当前可见页面的位置
func currentVisibleLocation() -> RDEPUBLocation? {
runtime.currentVisibleLocation()
}
/// 获取持久化存储的阅读位置
func persistenceLocation() -> RDEPUBLocation? {
readerContext.persistenceLocation()
}
/// 持久化当前阅读位置
func persist(location: RDEPUBLocation) {
readerContext.persist(location: location)
}
/// 更新当前文本选区状态
func updateCurrentSelection(_ selection: RDEPUBSelection?) {
runtime.annotationCoordinator.updateCurrentSelection(selection)
}
/// 将选区限定到指定 spine 范围内
func scopedSelection(
_ selection: RDEPUBSelection,
relativeToSpineIndex spineIndex: Int?
) -> RDEPUBSelection? {
runtime.annotationCoordinator.scopedSelection(selection, relativeToSpineIndex: spineIndex)
}
/// 刷新可见内容并保留当前位置
func refreshVisibleContentPreservingLocation() {
runtime.refreshVisibleContentPreservingLocation()
}
/// 重建外部文本书籍
func rebuildExternalTextBook() {
runtime.rebuildExternalTextBook()
}
/// 更新阅读器 UI 装饰层(导航栏、工具栏等)
func updateReaderChrome() {
runtime.updateReaderChrome()
}
/// 更新书签按钮状态
func updateBookmarkChrome() {
runtime.updateBookmarkChrome()
}
/// 展示书签管理界面
func presentBookmarksManager() {
runtime.presentBookmarksManager()
}
/// 展示高亮标注管理界面
func presentHighlightsManager() {
runtime.presentHighlightsManager()
}
/// 展示标注创建界面
func presentAnnotationCreation() {
runtime.presentAnnotationCreation()
}
/// 处理选区菜单操作(复制、标注、分享等)
func handleSelectionMenuAction(_ action: RDEPUBAnnotationMenuAction, selection: RDEPUBSelection?) {
runtime.handleSelectionMenuAction(action, selection: selection)
}
/// 展示阅读设置界面
func presentSettings() {
runtime.presentSettings()
}
/// 使用闭包更新阅读器配置
func updateConfiguration(_ update: (inout RDEPUBReaderConfiguration) -> Void) {
var nextConfiguration = configuration
update(&nextConfiguration)
configuration = nextConfiguration
}
/// 设置屏幕亮度并持久化
func setScreenBrightness(_ brightness: CGFloat) {
currentBrightness = max(0, min(1, brightness))
persistReaderSettingsIfNeeded()
}
/// 持久化阅读器设置(亮度、配置等)
func persistReaderSettingsIfNeeded() {
let settings = RDEPUBReaderSettings.capture(
configuration: configuration,
brightness: currentBrightness
)
persistence?.saveReaderSettings(settings)
}
/// 判断配置变更是否需要重新分页
func requiresRepagination(
from oldConfiguration: RDEPUBReaderConfiguration,
to newConfiguration: RDEPUBReaderConfiguration
) -> Bool {
oldConfiguration.fontSize != newConfiguration.fontSize ||
oldConfiguration.fontChoice != newConfiguration.fontChoice ||
oldConfiguration.lineHeightMultiple != newConfiguration.lineHeightMultiple ||
oldConfiguration.numberOfColumns != newConfiguration.numberOfColumns ||
oldConfiguration.columnGap != newConfiguration.columnGap ||
oldConfiguration.reflowableContentInsets != newConfiguration.reflowableContentInsets ||
oldConfiguration.fixedContentInset != newConfiguration.fixedContentInset ||
oldConfiguration.fixedLayoutFit != newConfiguration.fixedLayoutFit ||
oldConfiguration.fixedLayoutSpreadMode != newConfiguration.fixedLayoutSpreadMode ||
oldConfiguration.textRenderingEngine != newConfiguration.textRenderingEngine
}
/// 判断配置变更是否需要刷新可见内容
func requiresVisibleRefresh(
from oldConfiguration: RDEPUBReaderConfiguration,
to newConfiguration: RDEPUBReaderConfiguration
) -> Bool {
oldConfiguration.theme != newConfiguration.theme ||
oldConfiguration.darkImageAdjustmentEnabled != newConfiguration.darkImageAdjustmentEnabled ||
oldConfiguration.darkImageBlendRatio != newConfiguration.darkImageBlendRatio
}
/// 展示目录界面
func presentTableOfContents() {
runtime.presentTableOfContents()
}
/// 处理返回操作
func handleBackAction() {
runtime.handleBackAction()
}
/// 处理错误:停止分页、隐藏加载指示器、显示错误信息并通知代理
func handle(error: Error) {
isRepaginating = false
hideLoading()
readerContext.clearActiveSnapshot()
textBook = nil
readerView.reloadData()
errorLabel.text = error.localizedDescription
errorLabel.isHidden = false
delegate?.epubReader(self, didFailWithError: error)
}
/// 显示加载指示器
func showLoading() {
errorLabel.isHidden = true
loadingIndicator.startAnimating()
}
/// 隐藏加载指示器
func hideLoading() {
loadingIndicator.stopAnimating()
}
/// 获取当前视口签名(用于检测视口变化)
func currentViewportSignature() -> RDEPUBViewportSignature? {
runtime.currentViewportSignature()
}
/// 检测并处理视口变化(旋转、尺寸变化等)
func handleViewportChangeIfNeeded(
reason: RDEPUBViewportChangeReason,
viewportSignature: RDEPUBViewportSignature? = nil
) {
runtime.handleViewportChangeIfNeeded(reason: reason, viewportSignature: viewportSignature)
}
/// 获取指定页面的搜索结果展示状态
func searchPresentation(for page: EPUBPage) -> RDEPUBSearchPresentation? {
runtime.searchPresentation(for: page)
}
/// 根据出版物阅读方向解析页面翻页方向
private func resolvedPageDirection() -> RDReaderView.PageDirection {
publication?.readingProgression == .rtl ? .rightToLeft : .leftToRight
}
}
// MARK: - 手势识别器代理
extension RDEPUBReaderController: UIGestureRecognizerDelegate {
/// 手势识别器代理,始终返回 true 允许手势触发
public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
true
}
}