带有渐变的iOS UIProgressView

use*_*505 6 gradient progress uiprogressview ios cagradientlayer

是否可以使用从左到右的渐变创建自定义ui进度视图?

我用以下代码尝试过:

    let gradientLayer = CAGradientLayer()
    gradientLayer.frame = self.frame

    gradientLayer.anchorPoint = CGPoint(x: 0, y: 0)
    gradientLayer.position = CGPoint(x: 0, y: 0)

    gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.0);
    gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.0);

    gradientLayer.colors = [
        UIColor.red,
        UIColor.green
    ]

    // Convert to UIImage
    self.layer.insertSublayer(gradientLayer, at: 0)
    self.progressTintColor = UIColor.clear
    self.trackTintColor = UIColor.black
Run Code Online (Sandbox Code Playgroud)

但不幸的是,梯度不可见.还有其他想法吗?

Adr*_*ian 9

查看UIProgressView文档,有这个属性:

progressImage

如果提供自定义图像,则会忽略progressTintColor属性.

考虑到这一点,最懒的方法是创建渐变图像并将其设置为 progressImage

我改编了这个扩展,使它更清洁,可扩展,更安全.

fileprivate extension UIImage {
    static func gradientImage(with bounds: CGRect,
                            colors: [CGColor],
                            locations: [NSNumber]?) -> UIImage? {

        let gradientLayer = CAGradientLayer()
        gradientLayer.frame = bounds
        gradientLayer.colors = colors
        // This makes it horizontal
        gradientLayer.startPoint = CGPoint(x: 0.0,
                                        y: 0.5)
        gradientLayer.endPoint = CGPoint(x: 1.0,
                                        y: 0.5)

        UIGraphicsBeginImageContext(gradientLayer.bounds.size)
        gradientLayer.render(in: UIGraphicsGetCurrentContext()!)
        guard let image = UIGraphicsGetImageFromCurrentImageContext() else { return nil }
        UIGraphicsEndImageContext()
        return image`
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我们已经有了一种"动态"创建渐变图像的方法,下面是如何使用它:

let gradientImage = UIImage.gradientImage(with: progressView.frame,
                                        colors: [UIColor.red.cgColor, UIColor.green.cgColor],
                                        locations: nil)
Run Code Online (Sandbox Code Playgroud)

从那里,你只需设置你progressView的progressImage,就像这样:

// I'm lazy...don't force unwrap this
progressView.progressImage = gradientImage!
progressView.setProgress(0.75, animated: true)
Run Code Online (Sandbox Code Playgroud)

  • 你需要确保 ProgressView.frame 有宽度和高度,否则它将在 `gradientLayer.render(in: UIGraphicsGetCurrentContext()!)` 上崩溃 (3认同)

Geo*_*kos 7

我遇到了同样的问题并通过创建渐变自定义视图解决了这个问题,然后我将其转换为图像并将其指定为进度视图轨迹图像.

然后我水平翻转进度,使进度条成为背景,轨迹图像成为前景.

这具有显示下面的渐变图像的视觉效果.

您只需记住将百分比反转为非常简单,请参阅下面的示例按钮和代码:

在此输入图像描述在此输入图像描述

SWIFT 3示例:

class ViewController: UIViewController {

    @IBOutlet weak var progressView: UIProgressView!   

    @IBAction func lessButton(_ sender: UIButton) {
        let percentage  = 20
        let invertedValue = Float(100 - percentage) / 100
        progressView.setProgress(invertedValue, animated: true)
    }

    @IBAction func moreButton(_ sender: UIButton) {
        let percentage  = 80
        let invertedValue = Float(100 - percentage) / 100
        progressView.setProgress(invertedValue, animated: true)
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        //create gradient view the size of the progress view
        let gradientView = GradientView(frame: progressView.bounds)

        //convert gradient view to image , flip horizontally and assign as the track image
        progressView.trackImage = UIImage(view: gradientView).withHorizontallyFlippedOrientation()

        //invert the progress view
        progressView.transform = CGAffineTransform(scaleX: -1.0, y: -1.0)

        progressView.progressTintColor = UIColor.black
        progressView.progress = 1

    }

}

extension UIImage{
    convenience init(view: UIView) {

        UIGraphicsBeginImageContext(view.frame.size)
        view.layer.render(in: UIGraphicsGetCurrentContext()!)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        self.init(cgImage: (image?.cgImage)!)

    }
}

@IBDesignable
class GradientView: UIView {

    private var gradientLayer = CAGradientLayer()
    private var vertical: Bool = false

    override func draw(_ rect: CGRect) {
        super.draw(rect)
        // Drawing code

        //fill view with gradient layer
        gradientLayer.frame = self.bounds

        //style and insert layer if not already inserted
        if gradientLayer.superlayer == nil {

            gradientLayer.startPoint = CGPoint(x: 0, y: 0)
            gradientLayer.endPoint = vertical ? CGPoint(x: 0, y: 1) : CGPoint(x: 1, y: 0)
            gradientLayer.colors = [UIColor.green.cgColor, UIColor.red.cgColor]
            gradientLayer.locations = [0.0, 1.0]

            self.layer.insertSublayer(gradientLayer, at: 0)
        }
    }

}
Run Code Online (Sandbox Code Playgroud)