import UIKit /// 阅读器数据源协议 /// 上层控制器通过实现此协议,向 RDReaderView 提供页面数量、内容视图和工具栏。 /// 所有方法由 RDReaderView 在需要渲染页面时回调。 @objc public protocol RDReaderDataSource: NSObjectProtocol { /// 返回阅读器的总页数 func pageCountOfReaderView(readerView: RDReaderView) -> Int /// 返回指定页码的内容视图 func pageContentView(readerView: RDReaderView, pageNum: Int, containerView: UIView?) -> UIView /// 返回指定页码的唯一标识符,用于 UICollectionViewCell 复用 func pageIdentifier(readerView: RDReaderView, pageNum: Int) -> String? /// 返回顶部工具栏视图(可选),点击屏幕中央时会显示/隐藏 @objc optional func topToolView(readerView: RDReaderView) -> UIView? /// 返回底部工具栏视图(可选),点击屏幕中央时会显示/隐藏 @objc optional func bottomToolView(readerView: RDReaderView) -> UIView? } /// 与内容格式无关的统一分页提供者协议。 /// 逐步替代面向 EPUB 命名的 ``RDReaderDataSource``,方便后续复用到 PDF 等其他阅读场景。 @objc public protocol RDReaderPageProvider: NSObjectProtocol { func numberOfPages(in readerView: RDReaderView) -> Int func readerView(_ readerView: RDReaderView, viewForPageAt index: Int, reusableView: UIView?) -> UIView @objc optional func pageIdentifier(in readerView: RDReaderView, index: Int) -> String? @objc optional func readerViewTopChrome(_ readerView: RDReaderView) -> UIView? @objc optional func readerViewBottomChrome(_ readerView: RDReaderView) -> UIView? } /// 阅读器代理协议 /// 上层控制器通过实现此协议,接收翻页和横竖屏切换事件 @objc public protocol RDReaderDelegate: NSObjectProtocol { /// 翻页回调,当当前显示页码变化时触发 func pageNum(readerView: RDReaderView, pageNum: Int) /// 横竖屏切换时回调,可在此重新分页 @objc optional func readerViewOrientationWillChange(readerView: RDReaderView, isLandscape: Bool) } public protocol RDReaderPageNavigating: AnyObject { var currentPage: Int { get } func reloadPages() func transition(to page: Int, animated: Bool) } // MARK: - 枚举 extension RDReaderView { /// 翻页模式枚举,决定 RDReaderView 使用哪种底层视图来展示内容 public enum DisplayType { /// 仿真翻页:使用 UIPageViewController,模拟真实翻书效果 case pageCurl /// 水平滚动:使用 UICollectionView + 自定义布局,每屏一项,水平分页 case horizontalScroll /// 垂直滚动:使用 UICollectionView,全宽项目,垂直连续滚动 case verticalScroll } /// 翻页方向枚举 public enum PageDirection { /// 从左往右翻页(默认,适用于中文/英文书籍) case leftToRight /// 从右往左翻页(适用于日文漫画等) case rightToLeft } } // MARK: - Legacy 适配器 final class RDReaderLegacyDataSourceAdapter: NSObject, RDReaderPageProvider { weak var dataSource: RDReaderDataSource? func numberOfPages(in readerView: RDReaderView) -> Int { dataSource?.pageCountOfReaderView(readerView: readerView) ?? 0 } func readerView(_ readerView: RDReaderView, viewForPageAt index: Int, reusableView: UIView?) -> UIView { dataSource?.pageContentView(readerView: readerView, pageNum: index, containerView: reusableView) ?? UIView() } func pageIdentifier(in readerView: RDReaderView, index: Int) -> String? { dataSource?.pageIdentifier(readerView: readerView, pageNum: index) } func readerViewTopChrome(_ readerView: RDReaderView) -> UIView? { dataSource?.topToolView?(readerView: readerView) } func readerViewBottomChrome(_ readerView: RDReaderView) -> UIView? { dataSource?.bottomToolView?(readerView: readerView) } }