快速制作多色条

时间:2016-02-13 18:03:13

标签: ios swift

我正在尝试制作一条线(基本上是UIView),它具有固定的高度和宽度,并分为九个段。我希望能够控制每个段的高度及其颜色。例如。我希望第一段是黄色的,占线总高度的30%,第二段是红色,总高度的8%等。

我对Swift并不熟练,所以我的解决方案是制作9个UIViews,在我的故事板上将它们叠加在一起,然后手动设置每个视图的高度和背景颜色,所以它们看起来很像就像一条五彩线。是否有更清洁,体积更小的解决方案?感谢

3 个答案:

答案 0 :(得分:5)

我强烈建议您使用Core Graphics。

由于绘图很简单(您只想在视图中堆叠一些彩色线条),您可以通过继承UIView并覆盖drawRect()并在Core中绘制它们来轻松实现此目的图形。

它肯定比添加9个子视图更清晰!

这样的事情应该达到预期的效果:

class LineView : UIView {

    let colors:[UIColor] = [UIColor.redColor(), UIColor.blueColor(), UIColor.greenColor()]
    let values:[CGFloat] = [0.35, 0.45, 0.2]

    override func drawRect(rect: CGRect) {

        let r = self.bounds // the view's bounds
        let numberOfSegments = values.count // number of segments to render

        let ctx = UIGraphicsGetCurrentContext() // get the current context

        var cumulativeValue:CGFloat = 0 // store a cumulative value in order to start each line after the last one
        for i in 0..<numberOfSegments {

            CGContextSetFillColorWithColor(ctx, colors[i]) // set fill color to the given color
            CGContextFillRect(ctx, CGRectMake(0, cumulativeValue*r.size.height, r.size.width, values[i]*r.size.height)) // fill that given segment

            cumulativeValue += values[i] // increment cumulative value
        }
    }
}

更进一步......

您可以允许从colors类外部更改valuesLineView属性,从而提供更大的灵活性。您只需覆盖didSet即可在属性更改时触发重绘视图。

例如:

class LineView : UIView {

    /// An array of optional UIColors (clearColor is used when nil is provided) defining the color of each segment.
    var colors : [UIColor?] = [UIColor?]() {
        didSet {
            self.setNeedsDisplay()
        }
    }

    /// An array of CGFloat values to define how much of the view each segment occupies. Should add up to 1.0.
    var values : [CGFloat] = [CGFloat]() {
        didSet {
            self.setNeedsDisplay()
        }
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = UIColor.clearColor()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override func drawRect(rect: CGRect) {

        let r = self.bounds // the view's bounds
        let numberOfSegments = values.count // number of segments to render

        let ctx = UIGraphicsGetCurrentContext() // get the current context

        var cumulativeValue:CGFloat = 0 // store a cumulative value in order to start each line after the last one
        for i in 0..<numberOfSegments {

            CGContextSetFillColorWithColor(ctx, colors[i]?.CGColor ?? UIColor.clearColor().CGColor) // set fill color to the given color if it's provided, else use clearColor
            CGContextFillRect(ctx, CGRectMake(0, cumulativeValue*r.size.height, r.size.width, values[i]*r.size.height)) // fill that given segment

            cumulativeValue += values[i] // increment cumulative value
        }
    }
}

<强>用法:

let lineView = LineView(frame: CGRectMake(50, 50, 20, view.bounds.size.height-100))

lineView.colors = [
    UIColor(red: 1.0, green: 31.0/255.0, blue: 73.0/255.0, alpha: 1.0), // red
    UIColor(red:1.0, green: 138.0/255.0, blue: 0.0, alpha:1.0), // orange
    UIColor(red: 122.0/255.0, green: 108.0/255.0, blue: 1.0, alpha: 1.0), // purple
    UIColor(red: 0.0, green: 100.0/255.0, blue: 1.0, alpha: 1.0), // dark blue
    UIColor(red: 100.0/255.0, green: 241.0/255.0, blue: 183.0/255.0, alpha: 1.0), // green
    UIColor(red: 0.0, green: 222.0/255.0, blue: 1.0, alpha: 1.0) // blue
]
lineView.values = [0.15, 0.1, 0.35, 0.15, 0.1, 0.15]

view.addSubview(lineView);

enter image description here

(我这里只添加了6种颜色,但您可以添加任意数量的颜色。)

完整项目:https://github.com/hamishknight/Color-Segment-Line-View

答案 1 :(得分:2)

我刚刚意识到这不是你需要的。 无论如何,我都会留下答案,以便将来可能对其他人有所帮助。

确保您的线视图拥有自己的UIView子类,以便我们可以覆盖drawRect并实现您的目标。

然后简单实现将是:

class BarLine: UIView {

    override func drawRect(rect: CGRect) {

        //Height of each segment, in percentage
        var heights  : [CGFloat]    = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]

        //Lets create 9 rects and set each rect width to be 1/9th of the view size, then add them to the array
        let width   : CGFloat   = rect.size.width / 9.0


        var i       : Int       = Int()

        //Loop to generate 9 segmnets
        for (i = 0; i < 9; i++) {

            //Each rect origin must be translated by i * width
            let origin  = CGPointMake(CGFloat(i) * width, rect.height)

            //Generate a random color
            let color   = UIColor(red: heights[i], green: 0.5, blue: 0.5, alpha: 1)
            let segment = CGRect(x: origin.x, y: origin.y, width: width, height: -heights[i] * rect.height)

            //Set the color
            color.set()

            //Add the segment to the view by drawing it
            UIRectFill(segment)

        }


    }

}

这会产生类似的东西:

enter image description here

(请记住将您的UIView类设置为IB中的自定义类)

我希望这有帮助

答案 2 :(得分:1)

为了使@Hamish 代码与 Swift 5 兼容,这里是 LineView 类(并在 draw->fill 中反转宽度和高度以使其水平):

import UIKit

public class ColorLineView : UIView {

    public var colors : [UIColor?] = [UIColor?]() {
        didSet {
            self.setNeedsDisplay()
        }
    }

    public var values : [CGFloat] = [CGFloat]() {
        didSet {
            self.setNeedsDisplay()
        }
    }

    public override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = .clear
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    public override func draw(_ rect: CGRect) {

        let r = self.bounds
        let numberOfSegments = values.count

        guard let ctx = UIGraphicsGetCurrentContext() else { return }

        var cumulativeValue:CGFloat = 0
        for i in 0..<numberOfSegments {

            ctx.setFillColor(colors[i]?.cgColor ?? UIColor.clear.cgColor)
            ctx.fill(CGRect(x: 0, y: cumulativeValue*r.size.height, width: r.size.width, height: values[i]*r.size.height))

            cumulativeValue += values[i]
        }
    }
}