如何让UIProgressView的progressImage随进度逐步显示而非压缩?
解决UIProgressView进度图片逐步显示(而非压缩)的问题
默认的UIProgressView设置progressImage时,会自动将图片拉伸/压缩以适配进度条宽度,无法实现"随进度逐步显示图片局部区域"的效果。以下是两种可行的解决方案:
方案一:自定义进度视图(推荐,无版本兼容风险)
直接创建自定义视图来模拟进度条逻辑,完全控制图片的显示方式:
class CustomProgressView: UIView { private let progressImageView = UIImageView() private let maskLayer = CAShapeLayer() // 进度值范围0~1 var progress: CGFloat = 0.0 { didSet { updateMask() } } var progressImage: UIImage? { didSet { progressImageView.image = progressImage // 保持图片原始比例,仅从左侧开始显示 progressImageView.contentMode = .left progressImageView.clipsToBounds = true } } override init(frame: CGRect) { super.init(frame: frame) setupViews() } required init?(coder: NSCoder) { super.init(coder: coder) setupViews() } private func setupViews() { progressImageView.frame = bounds progressImageView.autoresizingMask = [.flexibleWidth, .flexibleHeight] addSubview(progressImageView) maskLayer.fillColor = UIColor.black.cgColor progressImageView.layer.mask = maskLayer } private func updateMask() { // 根据进度计算遮罩显示区域 let maskRect = CGRect(x: 0, y: 0, width: bounds.width * progress, height: bounds.height) maskLayer.path = UIBezierPath(rect: maskRect).cgPath } override func layoutSubviews() { super.layoutSubviews() updateMask() } }
使用方式:
// 初始化自定义进度条 let customProgress = CustomProgressView(frame: CGRect(x: 20, y: 100, width: 300, height: 20)) customProgress.progressImage = UIImage(named: "your_progress_image") view.addSubview(customProgress) // 更新进度(示例:模拟加载进度) DispatchQueue.main.asyncAfter(deadline: .now() + 1) { customProgress.progress = 0.3 } DispatchQueue.main.asyncAfter(deadline: .now() + 2) { customProgress.progress = 0.7 } DispatchQueue.main.asyncAfter(deadline: .now() + 3) { customProgress.progress = 1.0 }
方案二:修改系统UIProgressView的内部视图(有版本兼容风险)
通过KVC获取系统UIProgressView的私有progressImageView,给它添加遮罩层来控制显示区域:
// 假设已创建UIProgressView实例progressView if let progressImageView = progressView.value(forKey: "progressImageView") as? UIImageView { progressImageView.contentMode = .left progressImageView.clipsToBounds = false let maskLayer = CAShapeLayer() maskLayer.fillColor = UIColor.black.cgColor progressImageView.layer.mask = maskLayer // 监听进度变化更新遮罩 progressView.addObserver(self, forKeyPath: "progress", options: .new, context: nil) } // 实现观察者方法更新遮罩 override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { guard let progressView = object as? UIProgressView, keyPath == "progress" else { super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) return } if let progressImageView = progressView.value(forKey: "progressImageView") as? UIImageView, let maskLayer = progressImageView.layer.mask as? CAShapeLayer { let maskRect = CGRect(x: 0, y: 0, width: progressView.bounds.width * progressView.progress, height: progressView.bounds.height) maskLayer.path = UIBezierPath(rect: maskRect).cgPath } } // 记得在销毁时移除观察者 deinit { progressView.removeObserver(self, forKeyPath: "progress") }
注意:该方案依赖系统私有属性,可能在iOS版本更新后失效,或存在App Store审核风险,仅适合临时快速实现。
内容的提问来源于stack exchange,提问作者s g
相关产品推荐
相关产品推荐

