如何从任意ViewController中便捷显示活动指示器?
兄弟,我太懂这种在多个ViewController里重复写活动指示器代码的糟心感了!不仅代码冗余,后期要改样式或者逻辑的时候,得一个个VC去改,简直是维护噩梦。下面给你几个优雅的解决思路,彻底告别重复代码:
方案1:给UIViewController写扩展(最推荐)
把活动指示器的创建、显示、隐藏逻辑封装到UIViewController的扩展里,所有VC都能直接调用,不用重复造轮子:
extension UIViewController { // 懒加载全局活动指示器,避免重复创建 private var activityIndicator: UIActivityIndicatorView { let indicator = UIActivityIndicatorView(style: .large) indicator.layer.cornerRadius = 10 indicator.backgroundColor = UIColor.black.withAlphaComponent(0.7) indicator.clipsToBounds = true indicator.center = view.center indicator.hidesWhenStopped = true return indicator } // 显示活动指示器,可选禁用用户交互 func showLoadingIndicator() { let indicator = activityIndicator view.addSubview(indicator) indicator.startAnimating() view.isUserInteractionEnabled = false } // 隐藏活动指示器,恢复用户交互 func hideLoadingIndicator() { activityIndicator.stopAnimating() activityIndicator.removeFromSuperview() view.isUserInteractionEnabled = true } }
用法示例:在任意ViewController里直接调用就行,比如网络请求场景:
// 发起请求前显示 showLoadingIndicator() // 网络请求完成后隐藏(记得在主线程调用) DispatchQueue.main.async { self.hideLoadingIndicator() }
方案2:自定义单例工具类
如果不想给ViewController扩展,也可以写一个单例工具类统一管理指示器:
class LoadingManager { static let shared = LoadingManager() private let indicator = UIActivityIndicatorView(style: .large) private init() { // 初始化时统一配置样式 indicator.layer.cornerRadius = 10 indicator.backgroundColor = UIColor.black.withAlphaComponent(0.7) indicator.clipsToBounds = true indicator.hidesWhenStopped = true } func show(on targetView: UIView) { indicator.center = targetView.center targetView.addSubview(indicator) indicator.startAnimating() targetView.isUserInteractionEnabled = false } func hide(from targetView: UIView) { indicator.stopAnimating() indicator.removeFromSuperview() targetView.isUserInteractionEnabled = true } }
用法示例:
// 显示 LoadingManager.shared.show(on: self.view) // 隐藏 LoadingManager.shared.hide(from: self.view)
方案3:封装自定义LoadingView(适合复杂样式)
如果需要带提示文字或者更个性化的加载样式,可以封装一个独立的LoadingView:
class CustomLoadingView: UIView { private let indicator = UIActivityIndicatorView(style: .large) private let tipLabel = UILabel() init(tipText: String = "加载中...") { super.init(frame: .zero) setupUI(tipText: tipText) } required init?(coder: NSCoder) { super.init(coder: coder) setupUI(tipText: "加载中...") } private func setupUI(tipText: String) { backgroundColor = UIColor.black.withAlphaComponent(0.7) layer.cornerRadius = 10 clipsToBounds = true // 配置提示文字 tipLabel.text = tipText tipLabel.textColor = .white tipLabel.textAlignment = .center tipLabel.font = UIFont.systemFont(ofSize: 14) // 用栈视图布局指示器和文字 let stackView = UIStackView(arrangedSubviews: [indicator, tipLabel]) stackView.axis = .vertical stackView.spacing = 12 stackView.translatesAutoresizingMaskIntoConstraints = false addSubview(stackView) // 自动布局约束 NSLayoutConstraint.activate([ stackView.centerXAnchor.constraint(equalTo: centerXAnchor), stackView.centerYAnchor.constraint(equalTo: centerYAnchor), stackView.widthAnchor.constraint(equalToConstant: 130), heightAnchor.constraint(equalToConstant: 130) ]) } func startLoading() { indicator.startAnimating() } func stopLoading() { indicator.stopAnimating() } }
用法示例:
// 创建并显示 let loadingView = CustomLoadingView(tipText: "正在获取数据...") loadingView.frame = view.bounds view.addSubview(loadingView) loadingView.startLoading() // 隐藏 loadingView.stopLoading() loadingView.removeFromSuperview()
这几个方案都能帮你彻底消除重复代码,其中方案1最简洁高效,适合大多数普通加载场景;如果需要定制化样式,方案3会更灵活。
内容的提问来源于stack exchange,提问作者pmlk
相关产品推荐
相关产品推荐

