SDK 化收尾: - 新增 RDPDFReaderView 本地 pod(阅读容器、成品控制器、划线/注释、画笔、 目录/设置面板、主题与持久化契约),Demo 精简为 PDFKit 页面提供者 + 持久化宿主 - Podfile/工程接入 RDPDFReaderView 与 SnapKit,示例书改用 PDF 阅读器示例文件 手机横屏单页竖滑修复: - cell 高度改为宽度适配后的纸张高度(sizeForItemAt + 宿主按页提供纵横比), 纵向超出一屏的内容由外层 collectionView 连续滚动承接,不再被裁掉 - 页面内部不再开启同向嵌套的兜底竖向拖动,修复外层滚动被吞、无法滚到下一页 - 修复 applyContentSize 先评估拖动开关后写 contentSize 的顺序缺陷 - 页码按视口中心命中 cell 计算,补 didEndDragging 兜底;旋转重锚点与 transitionToPage 改用真实布局位置 - 横竖屏同为竖滑时也重建 cell 并刷新全部可见页的适配配置 - 横屏单页点击不再跳页,只显隐工具栏;翻页交给连续竖滑 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
67 lines
3.2 KiB
Swift
67 lines
3.2 KiB
Swift
import UIKit
|
||
|
||
extension RDPDFReaderView: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
|
||
public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||
pageCount()
|
||
}
|
||
|
||
public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||
let view = dataSource?.pageContentView(readerView: self, pageNum: indexPath.item) ?? UIView()
|
||
view.tag = indexPath.item
|
||
configureSpreadAlignment(for: view, page: indexPath.item)
|
||
configureInteraction(for: view)
|
||
if let cell = view.superview?.superview as? RDPDFReaderContentCell { return cell }
|
||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "fallback", for: indexPath) as! RDPDFReaderContentCell
|
||
cell.hostedView = view
|
||
return cell
|
||
}
|
||
|
||
public func collectionView(
|
||
_ collectionView: UICollectionView,
|
||
layout collectionViewLayout: UICollectionViewLayout,
|
||
sizeForItemAt indexPath: IndexPath
|
||
) -> CGSize {
|
||
// 手机横屏竖滑:cell 高度=宽度适配后的纸张高度,超出一屏的内容由
|
||
// collectionView 自身的连续滚动承接;页面未加载时先按一屏高占位。
|
||
if usesWidthFitVerticalScroll,
|
||
let height = verticalScrollWidthFitPageHeightProvider?(indexPath.item, bounds.width),
|
||
height > 0 {
|
||
return CGSize(width: bounds.width, height: height)
|
||
}
|
||
return usesLandscapeSpread
|
||
? CGSize(width: bounds.width / 2, height: bounds.height)
|
||
: bounds.size
|
||
}
|
||
|
||
public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
|
||
updateCurrentPageAfterScroll(scrollView)
|
||
}
|
||
|
||
public func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
|
||
// 竖滑是连续滚动(isPagingEnabled = false),轻推后直接停下不会触发
|
||
// 减速回调;此处兜底,否则页码停留在旧值。
|
||
if !decelerate { updateCurrentPageAfterScroll(scrollView) }
|
||
}
|
||
|
||
private func updateCurrentPageAfterScroll(_ scrollView: UIScrollView) {
|
||
guard currentDisplayType != .pageCurl else { return }
|
||
if currentDisplayType == .verticalScroll {
|
||
// 宽度适配下各 cell 高度不同,页码取视口中心命中的 cell。
|
||
// 顶部/底部回弹时中心点会越出内容范围,钳制回内容内再取 cell。
|
||
let centerY = scrollView.contentOffset.y + scrollView.bounds.height / 2
|
||
let center = CGPoint(
|
||
x: scrollView.bounds.width / 2,
|
||
y: min(max(0, centerY), max(0, collectionView.contentSize.height - 1))
|
||
)
|
||
if let indexPath = collectionView.indexPathForItem(at: center) {
|
||
currentPage = indexPath.item
|
||
} else if let first = collectionView.indexPathsForVisibleItems.min(by: { $0.item < $1.item }) {
|
||
currentPage = first.item
|
||
}
|
||
return
|
||
}
|
||
let value = scrollView.contentOffset.x / max(bounds.width, 1)
|
||
currentPage = Int(value.rounded()) * (usesLandscapeSpread ? 2 : 1)
|
||
}
|
||
}
|