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

如何让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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 14:45:56