UIProgressView进度不更新问题求助
UIProgressView进度不更新问题求助
我来帮你分析下问题出在哪,以及怎么修复:
首先,你的代码里有两个核心问题:UI布局缺失和主队列阻塞导致界面无法实时刷新,咱们一个个说:
1. 先解决ProgressView的布局问题
你现在只是把progressView add到alert的view上,但完全没设置约束或者frame,这会导致progressView的位置和大小都不对,甚至可能显示异常(比如你看到的灰色初始状态,很可能是因为控件没正确布局,系统没法正确渲染它的进度)。
先给progressView加上约束,确保它能在alert里正常显示:
// 先关闭自动转换约束,避免和手动约束冲突 progressView.translatesAutoresizingMaskIntoConstraints = false alertView.view.addSubview(progressView) // 添加具体约束,让进度条在alert底部左右留边 NSLayoutConstraint.activate([ progressView.leadingAnchor.constraint(equalTo: alertView.view.leadingAnchor, constant: 20), progressView.trailingAnchor.constraint(equalTo: alertView.view.trailingAnchor, constant: -20), progressView.bottomAnchor.constraint(equalTo: alertView.view.bottomAnchor, constant: -20), progressView.heightAnchor.constraint(equalToConstant: 4) ])
2. 进度条不实时更新的核心原因
你现在把所有进度修改、刷新操作都塞在同一个主队列闭包里同步执行——UIKit的界面更新是依赖RunLoop每一轮循环来渲染的,你一下子把progressView.progress从0→0.5→1.0全改完,系统根本没机会在中间刷新界面,只会直接显示最后一次修改后的状态。而且如果refreshStatData和refreshStatDisplay是耗时操作(比如读取数据、计算统计值),还会直接阻塞主队列,导致整个界面卡住,连alert的动画都出不来。
修复后的完整代码
我们把耗时操作放到后台队列,每完成一步就回到主队列更新进度,给系统留足渲染时间:
override func viewDidLoad() { super.viewDidLoad() // 别忘了调用super!这是UIViewController生命周期的必要操作 tableView.sectionHeaderHeight = 0 self.navigationController?.isNavigationBarHidden = true self.parent?.dismiss(animated: true, completion: nil) let alertView = UIAlertController(title: "Please wait", message: "Loading stats...", preferredStyle: .alert) let progressView = UIProgressView(progressViewStyle: .default) progressView.translatesAutoresizingMaskIntoConstraints = false alertView.view.addSubview(progressView) // 设置进度条约束 NSLayoutConstraint.activate([ progressView.leadingAnchor.constraint(equalTo: alertView.view.leadingAnchor, constant: 20), progressView.trailingAnchor.constraint(equalTo: alertView.view.trailingAnchor, constant: -20), progressView.bottomAnchor.constraint(equalTo: alertView.view.bottomAnchor, constant: -20), progressView.heightAnchor.constraint(equalToConstant: 4) ]) present(alertView, animated: true) { // present完成后,先初始化进度为0 progressView.progress = 0.0 // 把耗时的刷新操作放到后台队列,避免阻塞主队列 DispatchQueue.global(qos: .userInitiated).async { [weak self] in guard let self = self else { return } // 第一步:刷新数据(耗时操作放后台) self.refreshStatData() // 回到主队列更新进度,让系统渲染 DispatchQueue.main.async { progressView.progress = 0.5 } // 第二步:刷新显示逻辑(同样耗时的话也放后台) self.refreshStatDisplay() // 回到主队列更新进度并结束流程 DispatchQueue.main.async { progressView.progress = 1.0 // 加个短暂延迟,让用户能看到进度条满的状态再关闭alert DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { alertView.dismiss(animated: true) { self.tableView.isHidden = false } } } } } }
关键修改点说明:
- 给progressView补了AutoLayout约束,确保它在alert里位置、大小正确,样式渲染正常
- 把
refreshStatData和refreshStatDisplay放到后台队列执行,避免阻塞主队列导致UI卡住 - 每完成一个后台任务就回到主队列更新进度,给系统留足时间渲染界面变化
- 最后加了
asyncAfter延迟关闭alert,避免进度条刚到100%就消失,用户看不到完整过程 - 用
[weak self]避免循环引用,这是iOS开发里的好习惯,能防止内存泄漏
这样修改后,你就能看到进度条从0→50%→100%的完整变化过程了~
备注:内容来源于stack exchange,提问作者Marc Murphy
相关产品推荐
相关产品推荐

