75 lines
2.0 KiB
Swift
75 lines
2.0 KiB
Swift
//
|
|
// GlobalLoadingManager.swift
|
|
// suixinkan
|
|
//
|
|
|
|
import UIKit
|
|
|
|
/// 全局 Loading 管理器,对齐 Android `GlobalLoadingManager`。
|
|
@MainActor
|
|
final class GlobalLoadingManager {
|
|
|
|
static let shared = GlobalLoadingManager()
|
|
|
|
private var loadingCount = 0
|
|
private weak var hostWindow: UIWindow?
|
|
private var overlayView: GlobalLoadingOverlayView?
|
|
|
|
private init() {}
|
|
|
|
/// 当前是否正在展示 Loading。
|
|
var isShowing: Bool {
|
|
loadingCount > 0
|
|
}
|
|
|
|
/// 增加 Loading 引用计数并展示遮罩。
|
|
func show() {
|
|
loadingCount += 1
|
|
guard loadingCount == 1 else { return }
|
|
attachOverlayIfNeeded()
|
|
overlayView?.present()
|
|
}
|
|
|
|
/// 减少 Loading 引用计数,归零后立即隐藏遮罩。
|
|
func hide() {
|
|
guard loadingCount > 0 else { return }
|
|
loadingCount -= 1
|
|
guard loadingCount == 0 else { return }
|
|
overlayView?.dismiss()
|
|
overlayView?.removeFromSuperview()
|
|
}
|
|
|
|
/// 强制关闭所有 Loading。
|
|
func hideAll() {
|
|
loadingCount = 0
|
|
overlayView?.dismiss()
|
|
overlayView?.removeFromSuperview()
|
|
}
|
|
|
|
private func attachOverlayIfNeeded() {
|
|
guard let window = keyWindow else { return }
|
|
hostWindow = window
|
|
|
|
if overlayView == nil {
|
|
let overlay = GlobalLoadingOverlayView(frame: window.bounds)
|
|
overlay.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
overlay.isHidden = true
|
|
overlayView = overlay
|
|
}
|
|
|
|
guard let overlayView else { return }
|
|
if overlayView.superview !== window {
|
|
overlayView.removeFromSuperview()
|
|
window.addSubview(overlayView)
|
|
}
|
|
window.bringSubviewToFront(overlayView)
|
|
}
|
|
|
|
private var keyWindow: UIWindow? {
|
|
UIApplication.shared.connectedScenes
|
|
.compactMap { $0 as? UIWindowScene }
|
|
.flatMap(\.windows)
|
|
.first { $0.isKeyWindow }
|
|
}
|
|
}
|