ReadViewSDK/Sources/RDReaderView/ReaderView/RDReaderView+ToolView.swift
shenlei 0e7c0577e3 feat: add in-reader search and restructure documentation
- Add RDEPUBReaderSearchBarView with animated show/hide, keyword
  navigation, and match counting integrated into the reader controller
- Restructure docs: replace scattered design docs with consolidated
  BUSINESS_LOGIC.md and UML_CLASS_DIAGRAMS.md; update ARCHITECTURE.md
- Add SearchTests and FanrenParseTimeTest; enhance LargeBookOnDemandTests
- Add scripts/run_ui_regression.sh and summarize_ui_results.py for
  automated UI test execution and reporting

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-05 17:34:50 +08:00

128 lines
5.2 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// RDReaderView+ToolView.swift
// ReadViewSDK
//
// /
//
import UIKit
/// /
extension RDReaderView {
/// /
func tapCenter() {
refreshToolViewsFromProviderIfNeeded()
isShowToolView = !isShowToolView
if isShowToolView {
if let topToolView = topToolView {
installToolViewIfNeeded(topToolView, position: .top)
layoutIfNeeded()
topToolView.transform = CGAffineTransform(translationX: 0, y: -topToolView.bounds.height)
UIView.animate(withDuration: toolViewAnimationDuration) {
topToolView.transform = .identity
}
}
if let bottomToolView = bottomToolView {
installToolViewIfNeeded(bottomToolView, position: .bottom)
layoutIfNeeded()
bottomToolView.transform = CGAffineTransform(translationX: 0, y: bottomToolView.bounds.height)
UIView.animate(withDuration: toolViewAnimationDuration) {
bottomToolView.transform = .identity
}
}
collectionView.isUserInteractionEnabled = false
pageViewController.view.isUserInteractionEnabled = false
} else {
if let topToolView = topToolView {
UIView.animate(withDuration: toolViewAnimationDuration, animations: {
topToolView.transform = CGAffineTransform(translationX: 0, y: -topToolView.bounds.height)
}) { _ in
topToolView.removeFromSuperview()
}
}
if let bottomToolView = bottomToolView {
UIView.animate(withDuration: toolViewAnimationDuration, animations: {
bottomToolView.transform = CGAffineTransform(translationX: 0, y: bottomToolView.bounds.height)
}) { _ in
bottomToolView.removeFromSuperview()
}
}
collectionView.isUserInteractionEnabled = true
pageViewController.view.isUserInteractionEnabled = true
}
onToolViewVisibilityChanged?(isShowToolView)
}
///
func isHitView(_ hitView: UIView?, inside toolView: UIView, point: CGPoint) -> Bool {
if toolView.frame.contains(point) {
return true
}
guard let hitView else { return false }
return hitView === toolView || hitView.isDescendant(of: toolView)
}
///
enum ToolViewPosition {
///
case top
///
case bottom
}
///
func installToolViewIfNeeded(_ toolView: UIView, position: ToolViewPosition) {
guard toolView.superview !== self else { return }
toolView.removeFromSuperview()
addSubview(toolView)
toolView.translatesAutoresizingMaskIntoConstraints = false
let heightConstraint: NSLayoutConstraint
switch position {
case .top:
topToolViewHeightConstraint?.isActive = false
heightConstraint = toolView.heightAnchor.constraint(equalToConstant: resolvedToolViewHeight(for: .top))
topToolViewHeightConstraint = heightConstraint
NSLayoutConstraint.activate([
toolView.leadingAnchor.constraint(equalTo: leadingAnchor),
toolView.trailingAnchor.constraint(equalTo: trailingAnchor),
toolView.topAnchor.constraint(equalTo: topAnchor),
heightConstraint
])
case .bottom:
bottomToolViewHeightConstraint?.isActive = false
heightConstraint = toolView.heightAnchor.constraint(equalToConstant: resolvedToolViewHeight(for: .bottom))
bottomToolViewHeightConstraint = heightConstraint
NSLayoutConstraint.activate([
toolView.leadingAnchor.constraint(equalTo: leadingAnchor),
toolView.trailingAnchor.constraint(equalTo: trailingAnchor),
toolView.bottomAnchor.constraint(equalTo: bottomAnchor),
heightConstraint
])
}
}
/// safeAreaInsets
func updateToolViewHeightConstraintsIfNeeded() {
topToolViewHeightConstraint?.constant = resolvedToolViewHeight(for: .top)
bottomToolViewHeightConstraint?.constant = resolvedToolViewHeight(for: .bottom)
}
private func resolvedToolViewHeight(for position: ToolViewPosition) -> CGFloat {
let contentHeight: CGFloat = 52
switch position {
case .top:
return safeAreaInsets.top + contentHeight
case .bottom:
return safeAreaInsets.bottom + contentHeight
}
}
}