Files
ReadViewSDK/Sources/RDPDFReaderView/ReaderView/RDPDFReaderView+CollectionView.swift
T

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)
}
}