在Swift中,计算颜色时不会通过将颜色与透明颜色叠加来获得透明性

时间:2018-08-03 19:35:31

标签: swift colors

Colors overlaying

  • 我有一个原始UIView,其颜色为非透明orgColor
  • 这是由具有overlayColor且具有透明性(alpha通道)的覆盖UIView覆盖的。

给出这两种颜色orgColoroverlayColor,我该如何计算{strong>不具有任何透明度但在屏幕上完全相同的颜色calculatedColor好像两个视图都会被覆盖?

我为此编写了一个骨架函数(以展示其原理)。但是不知道如何计算(我在堆栈上发现了几篇有关颜色融合的文章,但实际上并没有消除结果的透明度...):

func calculateColor(orgColor: UIColor, overlayColor: UIColor) -> UIColor {
    var (r1, g1, b1, a1) = (CGFloat(0), CGFloat(0), CGFloat(0), CGFloat(0))
    var (r2, g2, b2, a2) = (CGFloat(0), CGFloat(0), CGFloat(0), CGFloat(0))

    orgColor.getRed(&r1, green: &g1, blue: &b1, alpha: &a1)
    overlayColor.getRed(&r2, green: &g2, blue: &b2, alpha: &a2)

    //how to put the alpha in the r g b? and integrate the overlay r g b?

    return color
}

2 个答案:

答案 0 :(得分:1)

覆盖颜色的Alpha(a2)告诉您颜色占总数的百分比,(1 - a2)告诉您原始颜色所占的百分比。因此,这是一个简单的计算:

func calculateColor(orgColor: UIColor, overlayColor: UIColor) -> UIColor {
    // Helper function to clamp values to range (0.0 ... 1.0)
    func clampValue(_ v: CGFloat) -> CGFloat {
        guard v > 0 else { return  0 }
        guard v < 1 else { return  1 }
        return v
    }

    var (r1, g1, b1, a1) = (CGFloat(0), CGFloat(0), CGFloat(0), CGFloat(0))
    var (r2, g2, b2, a2) = (CGFloat(0), CGFloat(0), CGFloat(0), CGFloat(0))

    orgColor.getRed(&r1, green: &g1, blue: &b1, alpha: &a1)
    overlayColor.getRed(&r2, green: &g2, blue: &b2, alpha: &a2)

    // Make sure the input colors are well behaved
    // Components should be in the range (0.0 ... 1.0)
    r1 = clampValue(r1)
    g1 = clampValue(g1)
    b1 = clampValue(b1)

    r2 = clampValue(r2)
    g2 = clampValue(g2)
    b2 = clampValue(b2)
    a2 = clampValue(a2)

    let color = UIColor(  red: r1 * (1 - a2) + r2 * a2,
                        green: g1 * (1 - a2) + g2 * a2,
                         blue: b1 * (1 - a2) + b2 * a2,
                        alpha: 1)

    return color
}

直觉上,这可以签出。如果覆盖颜色完全不透明(a2 == 1),则结果将是覆盖颜色。如果覆盖颜色是完全透明的(a2 == 0),则结果将是原始颜色。如果重叠色的Alpha为0.5,则您将获得恰好介于两种颜色中间的混合色。


在操场上对其进行测试:

// Make these colors anything you want
let c1 = UIColor(red: 27/255, green: 155/255, blue: 199/255, alpha: 1.0)
let c2 = UIColor(red: 188/255, green: 13/255, blue: 51/255, alpha: 0.37)

let c3 = calculateColor(orgColor: c1, overlayColor: c2)

let view1 = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
let view2 = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))

view1.backgroundColor = c1
view2.backgroundColor = c2

// Overlay view2 onto view1
view1.addSubview(view2)

// view3 has the calculated color
let view3 = UIView(frame: CGRect(x: 100, y: 0, width: 100, height: 100))
view3.backgroundColor = c3

// display the views side by side in view4
let view4 = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 100))
view4.addSubview(view1)
view4.addSubview(view3)

// display this view and see that the two halves match
view4

游乐场输出:

Playground output

答案 1 :(得分:1)

基于@vacawama的回答(全部归功于他!),我为UIColor编写了以下扩展名:

extension UIColor {

    func solidColorWhenOverlayed(by overlayColor: UIColor) -> UIColor {
        // Helper function to clamp values to range (0.0 ... 1.0)
        func clampValue(_ v: CGFloat) -> CGFloat {
            guard v > 0 else { return  0 }
            guard v < 1 else { return  1 }
            return v
        }

        var (r1, g1, b1, a1) = (CGFloat(0), CGFloat(0), CGFloat(0), CGFloat(0))
        var (r2, g2, b2, a2) = (CGFloat(0), CGFloat(0), CGFloat(0), CGFloat(0))

        getRed(&r1, green: &g1, blue: &b1, alpha: &a1)
        overlayColor.getRed(&r2, green: &g2, blue: &b2, alpha: &a2)

        // Make sure the input colors are well behaved
        // Components should be in the range (0.0 ... 1.0)
        // This to compensate for any "bad" colors = colors which have component values out of range
        r1 = clampValue(r1)
        g1 = clampValue(g1)
        b1 = clampValue(b1)

        r2 = clampValue(r2)
        g2 = clampValue(g2)
        b2 = clampValue(b2)
        a2 = clampValue(a2)

        return UIColor(  red  : r1 * (1 - a2) + r2 * a2,
                         green: g1 * (1 - a2) + g2 * a2,
                         blue : b1 * (1 - a2) + b2 * a2,
                         alpha: 1)
    }

}