【问题标题】:Wrong color & line Width with UIBezierPathUIBezierPath 的颜色和线宽错误
【发布时间】:2016-11-30 18:38:12
【问题描述】:

我在使用 UIBezierPath 时遇到了一个奇怪的问题,我的颜色和线宽没有正确呈现。

我正在绘制一系列具有主要和次要渐变的线条(如尺子)。主要渐变是长度较长的线条......

主要渐变:红色和线宽:2.0 小渐变:黄色和线宽:0.0(根据规格最细的线)

    override func draw(in ctx: CGContext) {
    if let _ = cameraControlSlider {
        guard gradationValues.count >= 0 else {
            return
        }

        let frame = CGRect(x: insetBy, y: 0, width: bounds.width - insetBy, height: bounds.height)
        ctx.clear(frame)

        let startx = Int(frame.origin.x)
        let endx = Int(frame.origin.x + frame.width)

        let incrementWidth = (endx - startx) / (gradationValuesOnScreen + 1)

        var counter = 1
        var x = startx + counter * incrementWidth

        while x < endx {

            var y1 = Int(frame.origin.y)
            var y2 = Int(frame.origin.y) + Int(frame.height)
            var lineWidth: Float = 2.0
            var color = UIColor.red

            if counter % majorGradationInterval != 1 {
                y1 = Int(frame.origin.y) + Int(frame.height / 4)
                y2 = Int(frame.origin.y + frame.height) - Int(frame.height / 4)
                lineWidth = 0.0
                color = UIColor.yellow
            }

            ctx.addPath(drawLine(in: ctx, x1: x, y1: y1, x2: x, y2: y2, color: color, lineWidth: lineWidth))
            counter += 1
            x = startx + counter * incrementWidth
        }
    }
}

func drawLine(in ctx: CGContext, x1: Int, y1: Int, x2: Int, y2: Int, color: UIColor, lineWidth: Float) -> CGPath {
    let path = UIBezierPath()

    ctx.setStrokeColor(color.cgColor)

    path.lineWidth = CGFloat(lineWidth)
    path.move(to: CGPoint(x: x1, y: y1))
    path.addLine(to: CGPoint(x: x2, y: y2))
    path.close()

    ctx.strokePath()

    return path.cgPath
}

基本上我希望较长的线条是红色和较粗的线条宽度,但颜色看起来是倒置的,线条宽度似乎没有任何影响。

从 draw 函数中可以看出,没有 UIColor red 与较小的线条长度相关联。我曾尝试在创建路​​径之前设置笔触颜色,但这似乎不起作用。

【问题讨论】:

    标签: ios swift3 uibezierpath


    【解决方案1】:

    这里有几个问题,但关键问题是drawLine 正在创建一个UIBezierPath 并正在调用strokePath。但是strokePath 并没有笔划您刚刚创建的UIBezierPath,而是之前添加到该上下文的路径。但是,由于直到您从drawLine 返回后才将该行添加到上下文中,所以一切都偏离了一个。另外,由于您将所有这些行添加到上下文中(而不是替换路径),因此您正在重复地重绘相同的行。

    您可以通过调用drawLine 而不是addPath(drawLine(...) 来修复它:

    override func draw(in ctx: CGContext) {
        ...
    
        while x < endx {
            ...
    
            drawLine(in: ctx, x1: x, y1: y1, x2: x, y2: y2, color: color, lineWidth: lineWidth)
    
            ...
        }
    }
    

    drawLine 不返回任何东西,而实际上只是绘制它:

    func drawLine(in ctx: CGContext, x1: Int, y1: Int, x2: Int, y2: Int, color: UIColor, lineWidth: Float) {
        let path = UIBezierPath()
    
        ctx.saveGState()
        ctx.setStrokeColor(color.cgColor)
        ctx.setLineWidth(CGFloat(lineWidth))
        path.move(to: CGPoint(x: x1, y: y1))
        path.addLine(to: CGPoint(x: x2, y: y2))
        ctx.addPath(path.cgPath)
        ctx.strokePath()
        ctx.restoreGState()
    }
    

    注意,我正在保存和恢复图形上下文,以便每次都可以绘制新的线段路径。另外,由于我正在抚摸上下文的路径,因此我在上下文而不是路径上调用setLineWidth。另外,这里没有显示,我发现如果我抚摸宽度为零的黄线,它们没有出现,所以我使用了1:

    注意,如果这是一个 UIView 子类,您可以进一步简化它(只需直接敲击 UIBezierPath 而不是搞乱 CoreGraphics,您可以将其设为 @IBDesignable 等)。但是如果你要实现draw(in:),我可能会做类似上面的事情。

    【讨论】:

    • 那是完美的@Rob。这说得通。但是,您提到它正在重绘,因为我们添加到上下文中。上面提到的更改以及保存 G 状态是否仍会发生这种情况。另外,什么时候使用 path.stroke 和 ctx.stroke。 Path.stroke 给了我无效上下文的错误,这就是我没有使用它的原因。 UIView 方法听起来很有趣。我得试试看。非常感谢。
    • 重新绘制,因为我们正在保存和恢复上下文,路径被重置为之前的无路径状态(例如,保存上下文,添加路径,描边,并将其恢复为无路径状态,然后重复)。
    • Re path.stroke,当您已经在图形上下文中时使用它(例如,在 UIView 子类的 draw(_ rect:) 中)。我真的很喜欢UIView 子类方法,因为代码更简单,您可以像任何其他UIView 一样将其添加到视图层次结构中,如果合适,请将其设置为@IBDesignable,并在您的故事板。但是你可能已经写了足够多的关于draw(in:) 模式的文章,这比需要的工作要多。幸运的是,这两种方法都可以正常工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-31
    • 1970-01-01
    • 2016-10-21
    相关资源
    最近更新 更多