116 lines
4.8 KiB
Swift
116 lines
4.8 KiB
Swift
import UIKit
|
||
|
||
/// 工具栏管理扩展:处理工具栏的显示/隐藏动画、安装、布局
|
||
extension RDReaderView {
|
||
|
||
/// 点击屏幕中央区域,切换工具栏的显示/隐藏
|
||
func tapCenter() {
|
||
refreshToolViewsFromProviderIfNeeded()
|
||
print("[Debug] tapCenter called, isShowToolView was: \(isShowToolView), topToolView: \(String(describing: topToolView)), onBack: \(String(describing: (topToolView as? RDEPUBReaderTopToolView)?.onBack))")
|
||
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
|
||
}
|
||
}
|
||
|
||
/// 判断点击命中的视图是否在指定工具栏内
|
||
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
|
||
])
|
||
}
|
||
}
|
||
|
||
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
|
||
}
|
||
}
|
||
}
|