You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从任意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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:11:55