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

为何UIActivityIndicatorView仅首次显示时动效正常,后续无动画?

问题分析与解决方案

问题原因

首次断网时动画正常,第二次断网时指示器无动画,核心原因是视图被反复从导航栏移除和添加:

  • 联网时将navigationItem.titleView设为nil,导致包含指示器的containerView被从视图层级中移除;
  • 配合activityIndicator.hidesWhenStopped = true的设置,调用stopAnimating()后指示器会被隐藏;
  • 第二次断网重新添加containerView时,虽然调用了startAnimating(),但由于视图刚被重新加入层级,动画状态未能正确触发。

解决方案

方案一:通过控制视图隐藏状态切换(推荐)

避免反复移除/添加containerView,始终将其作为titleView,仅通过isHidden控制显示/隐藏,状态更稳定:

  1. 在viewDidLoad中提前设置titleView并初始隐藏:
override func viewDidLoad() {
    label.text = "Waiting for network"
    label.font = UIFont.systemFont(ofSize: 17)
    label.textColor = .black
    
    containerView.addSubview(self.activityIndicator)
    containerView.addSubview(label)
    label.translatesAutoresizingMaskIntoConstraints = false
    self.activityIndicator.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
        self.activityIndicator.centerYAnchor.constraint(equalTo: containerView.centerYAnchor),
        self.activityIndicator.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
        label.centerYAnchor.constraint(equalTo: containerView.centerYAnchor),
        label.leadingAnchor.constraint(equalTo: self.activityIndicator.trailingAnchor, constant: 8),
        containerView.widthAnchor.constraint(equalTo: label.widthAnchor, constant: self.activityIndicator.frame.width + 8)
    ])
    
    // 提前设置titleView并初始隐藏
    self.navigationItem.titleView = self.containerView
    self.containerView.isHidden = true
    
    super.viewDidLoad()
}
  1. 修改onUpdate方法:
func onUpdate(_ isConnected: Bool) {
    print("isInternetConnected changed to: \(isConnected)")
    DispatchQueue.main.async {
        if isConnected {
            self.containerView.isHidden = true
            self.navigationItem.title = "Chats"
            self.activityIndicator.stopAnimating()
        } else {
            self.containerView.isHidden = false
            self.navigationItem.title = nil
            self.activityIndicator.startAnimating()
        }
    }
}

方案二:强制触发视图布局后启动动画

如果必须切换titleView,则在启动动画前强制完成视图布局,确保指示器处于有效视图层级中:

func onUpdate(_ isConnected: Bool) {
    print("isInternetConnected changed to: \(isConnected)")
    DispatchQueue.main.async {
        if isConnected {
            self.navigationItem.titleView = nil
            self.activityIndicator.stopAnimating()
            self.navigationItem.title = "Chats"
        } else {
            self.navigationItem.titleView = self.containerView
            // 强制完成布局,确保视图已加入层级
            self.containerView.layoutIfNeeded()
            // 手动取消隐藏并启动动画
            self.activityIndicator.isHidden = false
            self.activityIndicator.startAnimating()
        }
    }
}

总结

方案一避免了视图的频繁创建和销毁,符合iOS视图管理的最佳实践,状态稳定性更高,推荐优先使用。

内容的提问来源于stack exchange,提问作者Edward Tattsyrup

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 12:05:33