- 拆分 ContentDelegates/TextContentView 为独立协调器(InteractionCoordinator、LocationResolution、ExternalLinks、AttachmentTooltip) - 新增 RDEPUBAttachmentTooltipView/OverlayView 附件气泡提示 - 新增 RDEPUBDarkImageAdjuster 暗色模式图片亮度适配 - 新增 RDEPUBSelectionLoupeView 选区放大镜 - 新增 MetadataParseWorker/CancellationController 元数据解析取消机制 - 重构 PresentationRuntime/PaginationCoordinator 精简职责 - 优化 ChapterLoader/WarmupOrchestrator 异步章节加载 - CFI 模块微调与 NoteModels 更新 - 清理冗余文档,更新架构/UML/业务逻辑文档 Co-Authored-By: Claude <noreply@anthropic.com>
79 lines
2.7 KiB
Swift
79 lines
2.7 KiB
Swift
import UIKit
|
|
|
|
final class RDEPUBSelectionLoupeView: UIView {
|
|
|
|
private let imageView = UIImageView()
|
|
|
|
private let magnification: CGFloat = 1.45
|
|
|
|
private let captureSize = CGSize(width: 84, height: 84)
|
|
|
|
override init(frame: CGRect) {
|
|
super.init(frame: CGRect(origin: .zero, size: CGSize(width: 96, height: 96)))
|
|
isUserInteractionEnabled = false
|
|
backgroundColor = .clear
|
|
layer.shadowColor = UIColor.black.cgColor
|
|
layer.shadowOpacity = 0.18
|
|
layer.shadowRadius = 10
|
|
layer.shadowOffset = CGSize(width: 0, height: 5)
|
|
|
|
imageView.frame = bounds
|
|
imageView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
imageView.layer.cornerRadius = bounds.width / 2
|
|
imageView.layer.cornerCurve = .continuous
|
|
imageView.layer.borderWidth = 1.5
|
|
imageView.layer.borderColor = UIColor(white: 0.82, alpha: 0.95).cgColor
|
|
imageView.clipsToBounds = true
|
|
addSubview(imageView)
|
|
}
|
|
|
|
required init?(coder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
func present(sourceView: UIView, focusPoint: CGPoint, hostBounds: CGRect, targetPoint: CGPoint) {
|
|
imageView.image = snapshot(from: sourceView, focusPoint: focusPoint)
|
|
|
|
let targetCenter = CGPoint(
|
|
x: min(max(targetPoint.x, hostBounds.minX + bounds.width / 2), hostBounds.maxX - bounds.width / 2),
|
|
y: min(
|
|
max(hostBounds.minY + bounds.height / 2, targetPoint.y - 74),
|
|
hostBounds.maxY - bounds.height / 2
|
|
)
|
|
)
|
|
|
|
center = targetCenter
|
|
if isHidden {
|
|
alpha = 0
|
|
transform = CGAffineTransform(scaleX: 0.92, y: 0.92)
|
|
isHidden = false
|
|
UIView.animate(withDuration: 0.12) {
|
|
self.alpha = 1
|
|
self.transform = .identity
|
|
}
|
|
}
|
|
}
|
|
|
|
func dismiss() {
|
|
guard !isHidden else { return }
|
|
isHidden = true
|
|
alpha = 0
|
|
imageView.image = nil
|
|
}
|
|
|
|
private func snapshot(from sourceView: UIView, focusPoint: CGPoint) -> UIImage {
|
|
let renderer = UIGraphicsImageRenderer(size: captureSize)
|
|
return renderer.image { context in
|
|
let cgContext = context.cgContext
|
|
cgContext.setFillColor(UIColor.systemBackground.cgColor)
|
|
cgContext.fill(CGRect(origin: .zero, size: captureSize))
|
|
cgContext.translateBy(
|
|
x: captureSize.width / 2 - focusPoint.x * magnification,
|
|
y: captureSize.height / 2 - focusPoint.y * magnification
|
|
)
|
|
cgContext.scaleBy(x: magnification, y: magnification)
|
|
sourceView.layer.render(in: cgContext)
|
|
}
|
|
}
|
|
}
|