实现类似系统弹窗的动画效果:
import Foundation
import SnapKit
private var _coverKey = "alertCoverKey"
private var _constraintsClosureKey = "constraintsClosureKey"
protocol AlertSystemAnimationProtocol {
/// 弹出
func present()
/// 消失
func dismiss()
/// alert 与 cover 的约束
/// (注意调用顺序,应在 present 之前)
func constrains(_ closure: @escaping (ConstraintMaker) -> Void)
}
extension AlertSystemAnimationProtocol where Self: UIView {
private var _alertCover: UIView {
set {
objc_setAssociatedObject(self, &_coverKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
get {
return ((objc_getAssociatedObject(self, &_coverKey) as? UIView) ?? UIView())
}
}
private var _constrainsClosure: ((ConstraintMaker) -> Void)? {
set {
objc_setAssociatedObject(self, &_constraintsClosureKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
get {
guard let closure = objc_getAssociatedObject(self, &_constraintsClosureKey) as? ((ConstraintMaker) -> Void) else {
return nil
}
return closure
}
}
func constrains(_ closure: @escaping (ConstraintMaker) -> Void) {
_constrainsClosure = closure
}
func present() {
let cover = UIView()
cover.frame = UIScreen.main.bounds
cover.backgroundColor = UIColor.color(color: .black, alpha: 0.25)
cover.addSubview(self)
if let constraintsClosure = _constrainsClosure {
self.snp.makeConstraints(constraintsClosure)
} else {
self.snp.makeConstraints { make in
make.center.equalToSuperview()
make.left.equalTo(25.ratio)
}
}
cover.alpha = 0
self.alpha = 0.5
UIApplication.shared.keyWindow?.addSubview(cover)
cover.layoutIfNeeded()
self.transform = CGAffineTransform(scaleX: 1.1, y: 1.1)
UIView.animate(withDuration: 0.2, delay: 0, options: .curveEaseInOut) {
cover.alpha = 1
self.alpha = 1
self.transform = CGAffineTransform.identity
}
_alertCover = cover
}
func dismiss() {
UIView.animate(withDuration: 0.2, delay: 0, options: .curveEaseInOut) {
self._alertCover.alpha = 0
} completion: { isCompleted in
if isCompleted {
self.removeFromSuperview()
self._alertCover.removeFromSuperview()
}
}
}
}