69 lines
3.3 KiB
Swift
69 lines
3.3 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 }
|
||
// 用户主动滚动后保留其页内阅读位置;不再应用先前跳页等待异步布局的顶部锚点。
|
||
pendingWidthFitJumpPage = nil
|
||
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)
|
||
}
|
||
}
|