【问题标题】:How to show a static NON-animated progress bar using CoreGraphics in Swift?如何在 Swift 中使用 CoreGraphics 显示静态非动画进度条?
【发布时间】:2017-09-12 15:52:54
【问题描述】:

我想制作一个完全没有动画的静态进度条。我只想像 一样填充橙色部分,并且这张图片显示了(1 of 3)的进度,我想知道如何为(2 of 3)完成这个视图,最后完成进度条,如(3 3)。

谢谢您,我们将不胜感激。

【问题讨论】:

  • 创建UIView 的子类。为您的视图提供属性var progress = 0。覆盖 draw(_ rect: CGRect) 并使用 UIBezierPathmoveTolineToclose() 绘制 3 个线段。根据progress 的值(应为0-3)选择填充颜色灰色或橙色并填充路径。为didSet 添加一个属性观察者到progress 调用self.setNeedsDisplay()

标签: ios swift core-graphics core-animation


【解决方案1】:

这里有一个可工作的、可设计的类

import Foundation
import UIKit

@IBDesignable
class StaticLoad: UIView {

    enum Progress {
        case Empty
        case Filled(num: Int)
        case Full
    }

    @IBInspectable public var progressColor: UIColor?  {
        didSet {
            updateColor(progressColor: progressColor ?? tintColor, nonProgressColor: nonProgressColor)
        }
    }

    @IBInspectable public var nonProgressColor: UIColor = .gray {
        didSet {
            updateColor(progressColor: progressColor ?? tintColor, nonProgressColor: nonProgressColor)
        }
    }

    @IBInspectable public var numberOfSteps: Int = 3 {
        didSet {
            redrawSteps(step: numberOfSteps)
            updateColor(progressColor: progressColor ?? self.tintColor, nonProgressColor: nonProgressColor)
        }
    }

    @IBInspectable public var filledProgess: Int = 1 {
        didSet {
            if filledProgess >= numberOfSteps {
                filledProgess = numberOfSteps
                progress = .Full
            }
            if filledProgess <= 0 {
                filledProgess = 0
                progress = .Empty
            } else {
                progress = .Filled(num: filledProgess)
            }
            updateColor(progressColor: progressColor ?? tintColor, nonProgressColor: nonProgressColor)
        }
    }

    private var tip: CGFloat = 5
    private var progress: Progress = .Empty
    private var progressLayers: [CAShapeLayer] = []

    private func updateColor(progressColor: UIColor, nonProgressColor: UIColor) {
        switch progress {
        case .Empty:
            progressLayers.forEach { $0.fillColor = nonProgressColor.cgColor }
        case let .Filled(num):
            progressLayers.dropFirst(num).forEach { $0.fillColor = nonProgressColor.cgColor }
            progressLayers.dropLast(progressLayers.count - num).forEach { $0.fillColor = progressColor.cgColor }
        case .Full :
            progressLayers.forEach { $0.fillColor = progressColor.cgColor }
        }
    }

    private func redrawSteps(step: Int) {
        progressLayers.forEach { $0.removeFromSuperlayer() }
        progressLayers.removeAll()
        if step == 0 {
            let layer = CAShapeLayer()
            layer.frame = self.bounds
            progressLayers.append(layer)
        } else {
            var topLeft = CGPoint(x: 0, y: 0)
            let cgStep = CGFloat(step)
            let avaibleWidth = self.bounds.width - (2 * (cgStep - 1))
            let spacePerStep = avaibleWidth / cgStep
            let height = bounds.height
            let halfHeight = height / 2
            for i in 0..<step {

                let layer = CAShapeLayer()
                let bezier = UIBezierPath()
                bezier.move(to: topLeft)
                bezier.addLine(to: CGPoint(x: topLeft.x + spacePerStep, y: topLeft.y))
                if i + 1 != step {
                    bezier.addLine(to: CGPoint(x: topLeft.x + spacePerStep + tip, y: topLeft.y + halfHeight))
                }
                bezier.addLine(to: CGPoint(x: topLeft.x + spacePerStep, y: topLeft.y + height))
                bezier.addLine(to: CGPoint(x: topLeft.x, y: topLeft.y + height))
                if i != 0 {
                    bezier.addLine(to: CGPoint(x: topLeft.x + tip, y: topLeft.y + halfHeight))
                }
                bezier.close()
                layer.path = bezier.cgPath
                progressLayers.append(layer)
                self.layer.addSublayer(layer)

                topLeft.x = topLeft.x + spacePerStep + 2
            }
        }
    }

    override func layoutSubviews() {
        redrawSteps(step: numberOfSteps)
        updateColor(progressColor: progressColor ?? tintColor, nonProgressColor: nonProgressColor)
    }

}

您所要做的就是从情节提要中获取一个 UIView 并创建自定义类 StaticLoad。您可以通过代码或情节提要更改numberOfSteps 属性来指定进度条中的条数,并通过filledProgress 填充进度条

如果您想要更大的箭头,只需更改 tip 属性,或为 bezierPath 指定另一个路径。

如果你不知道,@IBDesignable(建议如果一个类是可设计的,由于持续编译,它应该放在另一个框架而不是同一个项目中)允许故事板渲染视图和@IBInspectable 允许通过情节提要设置变量。

这是一个未优化的工作示例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多