ReadViewSDK/ReadViewDemo/Pods/SSAlertSwift/Sources/SSAlertSwift/SSAlertView.swift
2026-05-21 19:40:51 +08:00

313 lines
14 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.

//
// SSAlertView.swift
// SSAlert
//
// Created by yangsq on 2021/8/13.
//
import UIKit
extension SSAlertView {
public enum BackgroundMaskType {
///
case none
///
case clear
///
case black
}
}
fileprivate extension SSAlertView {
typealias HideCompletion = () -> Void
class HideCompletionData: NSObject {
var completion: HideCompletion?
}
}
open class SSAlertView: UIView {
/// customView
public var customEdgeInsets: UIEdgeInsets = .zero {
didSet {
setNeedsDisplay()
layoutIfNeeded()
}
}
///
public var animation: SSAlertAnimation
///
public private(set) var backgroundMask: UIView?
///
public var canTouchMaskHide: Bool = true
/// nil,
public var isTouchMaskHideAnimated: Bool? = nil
///
public private(set) var navigationController: UINavigationController?
public var isHideStatusBar = false {
didSet {
self.toViewContrller?.isHideStatusBar = isHideStatusBar
}
}
public var isShowNavWhenViewWillDisappear = true {
didSet {
self.toViewContrller?.isShowNavWhenViewWillDisappear = isShowNavWhenViewWillDisappear
}
}
private var onView: UIView
public private(set) var maskType: BackgroundMaskType
public private(set) var customView: UIView
private weak var fromViewController: UIViewController?
private weak var toViewContrller: SSAlertAnimationController?
private var presentAnimation: SSAlertPresentAnimation?
private var canPanDimiss: Bool = false
private var hideCompletions = [HideCompletionData]()
///
public init(customView: UIView,
onView: UIView,
animation: SSAlertAnimation = SSAlertDefaultAnmation(state: .fromCenter),
maskType: BackgroundMaskType = .black) {
self.animation = animation
self.onView = onView
self.maskType = maskType
self.customView = customView
super.init(frame: .zero)
makeUI()
}
/// ),canPanDimiss:
public convenience init(customView: UIView,
fromViewController: UIViewController,
animation: SSAlertAnimation = SSAlertDefaultAnmation(state: .fromCenter),
navigationControllerClass: UINavigationController.Type = UINavigationController.self,
maskType: BackgroundMaskType = .black,
canPanDimiss: Bool = true) {
let animaionVC = SSAlertAnimationController()
self.init(customView: customView, onView: animaionVC.view, animation: animation, maskType: maskType)
animaionVC.isHideStatusBar = self.isHideStatusBar
if let superViewController = superViewController(view: customView), superViewController != animaionVC {
animaionVC.addChild(superViewController)
superViewController.didMove(toParent: animaionVC)
}
self.canPanDimiss = canPanDimiss
self.fromViewController = fromViewController
let nav = navigationControllerClass.init(rootViewController: animaionVC)
nav.modalPresentationStyle = .custom
self.navigationController = nav
self.canPanDimiss = canPanDimiss
let animation = SSAlertPresentAnimation(navigationViewController: nav, animationView: customView, canPanDimiss: canPanDimiss)
self.navigationController!.transitioningDelegate = animation
self.navigationController!.modalPresentationCapturesStatusBarAppearance = true
self.presentAnimation = animation
self.toViewContrller = animaionVC
}
open override func layoutSubviews() {
super.layoutSubviews()
backgroundMask?.frame = CGRect(x: 0, y: 0, width: onView.ss_w, height: onView.ss_h)
customView.ss_x = customEdgeInsets.left
customView.ss_y = customEdgeInsets.top
customView.ss_w = frame.width - customEdgeInsets.left - customEdgeInsets.right
customView.ss_h = frame.height - customEdgeInsets.top - customEdgeInsets.bottom
}
private func makeUI() {
if maskType != .none {
let backgroundMask = UIButton()
backgroundMask.alpha = 0
onView.addSubview(backgroundMask)
backgroundMask.addTarget(self, action: #selector(backgroundMaskAction), for: .touchUpInside)
self.backgroundMask = backgroundMask
if maskType == .black {
backgroundMask.backgroundColor = UIColor.black.withAlphaComponent(0.3)
}
}
addSubview(customView)
onView.addSubview(self)
}
///
public func show(animated: Bool = true, completion: (() -> Void)? = nil) {
if navigationController != nil {
presentView(animated: animated, completion: completion)
} else {
showView(animated: animated, completion: completion)
}
}
///
public func hide(animated: Bool = true, completion: (() -> Void)? = nil) {
if navigationController != nil {
dimissView(animated: animated, completion: completion)
} else {
hideView(animated: animated, completion: completion)
}
}
///
/// - Parameter animated:
private func showView(animated: Bool = true, completion: (() -> Void)? = nil) {
isTouchMaskHideAnimated = animated
var customSize = customView.systemLayoutSizeFitting(UIView.layoutFittingExpandedSize)
if customView.ss_size != .zero {
customSize = customView.ss_size
}
let size = CGSize(width: customSize.width + customEdgeInsets.left + customEdgeInsets.right, height: customSize.height + customEdgeInsets.top + customEdgeInsets.bottom)
animation.showAnimationOfAnimationView(animationView: self, viewSize: size, animated: animated, completion: { _ in completion?() })
}
///
/// - Parameter animated:
private func hideView(animated: Bool = true, completion: (() -> Void)? = nil) {
var customSize = customView.systemLayoutSizeFitting(UIView.layoutFittingExpandedSize)
if customView.ss_size != .zero {
customSize = customView.ss_size
}
let size = CGSize(width: customSize.width + customEdgeInsets.left + customEdgeInsets.right, height: customSize.height + customEdgeInsets.top + customEdgeInsets.bottom)
animation.hideAnimationOfAnimationView(animationView: self, viewSize: size, animated: animated) { [weak self] _ in guard let self = self else { return false }
completion?()
self.hideCompletions.forEach { hideC in
hideC.completion?()
hideC.completion = nil
self.hideCompletions.removeAll(where: {$0 == hideC})
}
return false
}
}
///
/// - Parameter animated:
private func presentView(animated: Bool = true, completion: (() -> Void)? = nil) {
isTouchMaskHideAnimated = animated
var customSize = customView.systemLayoutSizeFitting(UIView.layoutFittingExpandedSize)
if customView.ss_size != .zero {
customSize = customView.ss_size
}
let size = CGSize(width: customSize.width + customEdgeInsets.left + customEdgeInsets.right, height: customSize.height + customEdgeInsets.top + customEdgeInsets.bottom)
presentAnimation?.animationCompletion(showAnimation: {
[weak self] in guard let self = self else { return }
self.animation.showAnimationOfAnimationView(animationView: self, viewSize: size, animated: animated) { _ in
self.presentAnimation?.setCompleteTransitionIsHide(isHide: false)
completion?()
}
})
self.presentAnimation?.duration = animation.animationDuration()
/// apppresnentmodalPresentationStyleCurrentContextpresentingVCtabbarVCtabbarVCdimisspresentedVCdimissdimisspresentigngVCdimiss,
/// definesPresentationContext = true,modalPresentationStyle = UIModalPresentationOverCurrentContextpresentigngVC self.navigationController,
/// UIModalPresentationOverCurrentContext UIModalPresentationCurrentContextstact
self.navigationController?.definesPresentationContext = true
self.navigationController?.modalPresentationStyle = .overCurrentContext
self.fromViewController?.present(self.navigationController!, animated: true, completion: nil)
if canPanDimiss {
dimissViewDragToHideAnimation(animated: animated)
}
}
///
/// - Parameter animated:
private func dimissView(animated: Bool = true, completion: (() -> Void)? = nil) {
var customSize = customView.systemLayoutSizeFitting(UIView.layoutFittingExpandedSize)
if customView.ss_size != .zero {
customSize = customView.ss_size
}
let size = CGSize(width: customSize.width + customEdgeInsets.left + customEdgeInsets.right, height: customSize.height + customEdgeInsets.top + customEdgeInsets.bottom)
presentAnimation?.animationCompletion(hideAnimation: {
[weak self] in guard let self = self else { return }
self.animation.hideAnimationOfAnimationView(animationView: self, viewSize: size, animated: animated) { _ in
return self.presentAnimation!.setCompleteTransitionIsHide(isHide: true)
}
})
self.presentAnimation?.duration = animation.animationDuration()
self.toViewContrller?.dismiss(animated: animated, completion: {
[weak self] in guard let self = self else { return }
completion?()
self.hideCompletions.forEach { hideC in
hideC.completion?()
hideC.completion = nil
self.hideCompletions.removeAll(where: {$0 == hideC})
}
})
}
private func dimissViewDragToHideAnimation(animated: Bool) {
var customSize = customView.systemLayoutSizeFitting(UIView.layoutFittingExpandedSize)
if customView.ss_size != .zero {
customSize = customView.ss_size
}
let size = CGSize(width: customSize.width + customEdgeInsets.left + customEdgeInsets.right, height: customSize.height + customEdgeInsets.top + customEdgeInsets.bottom)
presentAnimation?.animationCompletion(hideAnimation: {
[weak self] in guard let self = self else { return }
self.animation.hideAnimationOfAnimationView(animationView: self, viewSize: size, animated: animated) { _ in
return self.presentAnimation!.setCompleteTransitionIsHide(isHide: true)
}
},endCompletion: {
[weak self] in guard let self = self else { return }
self.hideCompletions.forEach { hideC in
hideC.completion?()
hideC.completion = nil
self.hideCompletions.removeAll(where: {$0 == hideC})
}
}, panDimissAnimation: { [weak self] point, frame in
guard let self = self else { return (0, 0.4) }
return self.animation.panToDimissTransilatePoint(point: point, panViewFrame: frame)
}, dimissAnimation: { [weak self] isCancel in guard let self = self else { return }
self.toViewContrller?.isDimiss = !isCancel
})
self.presentAnimation?.duration = animation.animationDuration()
}
public func refreshFrame(animated: Bool = true) {
var customSize = customView.systemLayoutSizeFitting(UIView.layoutFittingExpandedSize)
if customView.ss_size != .zero {
customSize = customView.ss_size
}
let size = CGSize(width: customSize.width + customEdgeInsets.left + customEdgeInsets.right, height: customSize.height + customEdgeInsets.top + customEdgeInsets.bottom)
animation.refreshAnimationOfAnimationView(animationView: self, viewSize: size, animated: animated, completion: nil)
}
@objc private func backgroundMaskAction() {
if canTouchMaskHide {
if fromViewController != nil {
dimissView(animated: isTouchMaskHideAnimated ?? false)
} else {
hideView(animated: isTouchMaskHideAnimated ?? false)
}
}
}
private func superViewController(view: UIView) -> UIViewController? {
var next = view.next
while next != nil {
if next is UIViewController {
return next as? UIViewController
} else {
next = next!.next
}
}
return nil
}
public func observeHideCompletion(completion: (() -> Void)?) {
let completionData = HideCompletionData()
completionData.completion = completion
self.hideCompletions.append(completionData)
}
required public init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}