Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/96.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
iOS在两种颜色之间的点查找颜色_Ios_Gradient_Uicolor_Blending_Linear Gradients - Fatal编程技术网

iOS在两种颜色之间的点查找颜色

iOS在两种颜色之间的点查找颜色,ios,gradient,uicolor,blending,linear-gradients,Ios,Gradient,Uicolor,Blending,Linear Gradients,我有一个问题:我需要能够采取两种颜色,使他们的'虚拟梯度'。然后我需要能够找到这条线上任何一点的颜色。我目前的做法是: if (fahrenheit < kBottomThreshold) { return [UIColor colorWithRed:kBottomR/255.0f green:kBottomG/255.0f blue:kBottomB/255.0f alpha:1]; } if (fahrenheit > kTopThreshold) { retur

我有一个问题:我需要能够采取两种颜色,使他们的'虚拟梯度'。然后我需要能够找到这条线上任何一点的颜色。我目前的做法是:

if (fahrenheit < kBottomThreshold)
{
    return [UIColor colorWithRed:kBottomR/255.0f green:kBottomG/255.0f blue:kBottomB/255.0f alpha:1];
}
if (fahrenheit > kTopThreshold)
{
    return [UIColor colorWithRed:kTopR/255.0f green:kTopG/255.0f blue:kTopB/255.0f alpha:1];
}

double rDiff = kTopR - kBottomR;
double gDiff = kTopG - kBottomG;
double bDiff = kTopB - kBottomB;

double tempDiff = kTopThreshold - kBottomThreshold;

double rValue;
double gValue;
double bValue;

rValue = kBottomR + ((rDiff/tempDiff) * fahrenheit);
gValue = kBottomG + ((gDiff/tempDiff) * fahrenheit);
bValue = kBottomB + ((bDiff/tempDiff) * fahrenheit);

return [UIColor colorWithRed:rValue/255.0f green:gValue/255.0f blue:bValue/255.0f alpha:1];
if(华氏kTopThreshold)
{
返回[UIColor COLOR WITH RED:kTopR/255.0f green:kTopG/255.0f blue:kTopB/255.0f alpha:1];
}
双rDiff=kTopR-kBottomR;
双gDiff=kTopG-kBottomG;
双bDiff=kTopB-kBottomB;
双tempDiff=kTopThreshold-kBottomThreshold;
双右值;
双重价值;
双b值;
rValue=kBottomR+((rDiff/tempDiff)*华氏度);
gValue=kBottomG+((gDiff/tempDiff)*华氏度);
b值=kBottomB+((bDiff/tempDiff)*华氏度);
返回[UIColor color with red:rValue/255.0f green:gValue/255.0f blue:bValue/255.0f alpha:1];
变量:

  • fahrenheit
    是一个传递到我的函数中的变量,它是我要查找颜色的虚拟行上的数字
  • kTopR
    kTopB
    kTopG
    是渐变一端的RGB值。它们的
    kBottom
    对应项也是如此
  • kBottomThreshold
    kTopThreshold
    是渐变的端点
我的问题是:
fahrenheit
越过梯度的两端时,梯度似乎“跳跃”到另一个值。

我已经包括了一个示例项目,托管在我的S3服务器上


你真的需要下载这个项目,并在模拟器/设备上试用,看看我的意思(除非你非常聪明,只要看一下代码就知道了)

问题是你没有从
法伦海特
中减去
kBottomThreshold

但让我们简化一下

首先,我们要将输入温度映射到[0…1]范围内的参数
t
。然后,我们希望将
t
映射到[
kBottomR
..
kTopR
]范围内的输出,也映射到[
kBottomG
..
kTopG
]范围内的输出,以及[
kBottomB
..
kTopB
]范围内的输出

UIColor *colorForDegreesFahrenheit(double fahrenheit) {
    double t = (fahrenheit - kBottomThreshold) / (kTopThreshold - kBottomThreshold);

    // Clamp t to the range [0 ... 1].
    t = MAX(0.0, MIN(t, 1.0));

    double r = kBottomR + t * (kTopR - kBottomR);
    double g = kBottomG + t * (kTopG - kBottomG);
    double b = kBottomB + t * (kTopB - kBottomB);

    return [UIColor colorWithRed:r/255 green:g/255 blue:b/255 alpha:1];
}

如果你的梯度比2色渐变更复杂,你可以考虑将CGRelistEnf绘制成临时的CGIMAGEVEF,并直接从图像缓冲器读取RGBA值。 以下是我用5个渐变停止点和颜色做的事情:

    CGFloat tmpImagewidth = 1000.0f; // Make this bigger or smaller if you need more or less resolution (number of different colors).
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    // create a gradient
    CGFloat locations[] = { 0.0,
        0.35,
        0.55,
        0.8,
        1.0 };
    NSArray *colors = @[(__bridge id) [UIColor redColor].CGColor,
                        (__bridge id) [UIColor greenColor].CGColor,
                        (__bridge id) [UIColor blueColor].CGColor,
                        (__bridge id) [UIColor yellowColor].CGColor,
                        (__bridge id) [UIColor redColor].CGColor,
                        ];
    CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef) colors, locations);
    CGPoint startPoint = CGPointMake(0, 0);
    CGPoint endPoint = CGPointMake(tmpImagewidth, 0);

    // create a bitmap context to draw the gradient to, 1 pixel high.
    CGContextRef context = CGBitmapContextCreate(NULL, tmpImagewidth, 1, 8, 0, colorSpace, kCGImageAlphaPremultipliedLast);

    // draw the gradient into it
    CGContextAddRect(context, CGRectMake(0, 0, tmpImagewidth, 1));
    CGContextClip(context);
    CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);

    // Get our RGB bytes into a buffer with a couple of intermediate steps...
    //      CGImageRef -> CFDataRef -> byte array
    CGImageRef cgImage = CGBitmapContextCreateImage(context);
    CGDataProviderRef provider = CGImageGetDataProvider(cgImage);
    CFDataRef pixelData = CGDataProviderCopyData(provider);

    // cleanup:
    CGGradientRelease(gradient);
    CGColorSpaceRelease(colorSpace);
    CGImageRelease(cgImage);
    CGContextRelease(context);

    const UInt8* data = CFDataGetBytePtr(pixelData);

    // we got all the data we need.
    // bytes in the data buffer are a succession of R G B A bytes

    // For instance, the color of the point 27% in our gradient is:
    CGFloat x = tmpImagewidth * .27;
    int pixelIndex = (int)x * 4; // 4 bytes per color
    UIColor *color = [UIColor colorWithRed:data[pixelIndex + 0]/255.0f
                                     green:data[pixelIndex + 1]/255.0f
                                      blue:data[pixelIndex + 2]/255.0f
                                     alpha:data[pixelIndex + 3]/255.0f];

    // done fetching color data, finally release the buffer
    CGDataProviderRelease(provider);
我并不是说这比上面答案中的“数学方法”要好,当然,在生成临时映像时会产生内存和cpu税。
然而,这样做的好处是,无论您需要多少个渐变停止,代码复杂度都保持不变…

Swift-3.0和&4.0

extension UIColor {
    func toColor(_ color: UIColor, percentage: CGFloat) -> UIColor {
        let percentage = max(min(percentage, 100), 0) / 100
        switch percentage {
        case 0: return self
        case 1: return color
        default:
            var (r1, g1, b1, a1): (CGFloat, CGFloat, CGFloat, CGFloat) = (0, 0, 0, 0)
            var (r2, g2, b2, a2): (CGFloat, CGFloat, CGFloat, CGFloat) = (0, 0, 0, 0)
            guard self.getRed(&r1, green: &g1, blue: &b1, alpha: &a1) else { return self }
            guard color.getRed(&r2, green: &g2, blue: &b2, alpha: &a2) else { return self }

            return UIColor(red: CGFloat(r1 + (r2 - r1) * percentage),
                           green: CGFloat(g1 + (g2 - g1) * percentage),
                           blue: CGFloat(b1 + (b2 - b1) * percentage),
                           alpha: CGFloat(a1 + (a2 - a1) * percentage))
        }
    }
}
用法:-

结果


我想扩展/修改@Sebastien Windal的答案,因为他的答案对我的用例非常有用,但可以通过直接从上下文获取像素数据来进一步改进(请参阅)

我用swift实现了他的答案,因此更改也用swift编写

在绘制渐变之前,只需将Int数组传递给上下文即可。然后,在绘制上下文时,将用像素数据填充阵列

let dataSize = tmpImagewidth * 1 * 4
var pixelData = [UInt8](repeating: 0, count: Int(dataSize))


let context = CGContext(data: &pixelData, width: Int(tmpImagewidth), height: 1, bitsPerComponent: 8, bytesPerRow: 4 * Int(tmpImagewidth), space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)
然后,我们可以先跳过创建图像,从中读取像素数据。

谢谢,我实现了扩展,以按百分比从颜色数组中获取中间颜色

extension Array where Element: UIColor {
    func intermediate(percentage: CGFloat) -> UIColor {
        let percentage = Swift.max(Swift.min(percentage, 100), 0) / 100
        switch percentage {
        case 0: return first ?? .clear
        case 1: return last ?? .clear
        default:
            let approxIndex = percentage / (1 / CGFloat(count - 1))
            let firstIndex = Int(approxIndex.rounded(.down))
            let secondIndex = Int(approxIndex.rounded(.up))
            let fallbackIndex = Int(approxIndex.rounded())

            let firstColor = self[firstIndex]
            let secondColor = self[secondIndex]
            let fallbackColor = self[fallbackIndex]

            var (r1, g1, b1, a1): (CGFloat, CGFloat, CGFloat, CGFloat) = (0, 0, 0, 0)
            var (r2, g2, b2, a2): (CGFloat, CGFloat, CGFloat, CGFloat) = (0, 0, 0, 0)
            guard firstColor.getRed(&r1, green: &g1, blue: &b1, alpha: &a1) else { return fallbackColor }
            guard secondColor.getRed(&r2, green: &g2, blue: &b2, alpha: &a2) else { return fallbackColor }

            let intermediatePercentage = approxIndex - CGFloat(firstIndex)
            return UIColor(red: CGFloat(r1 + (r2 - r1) * intermediatePercentage),
                           green: CGFloat(g1 + (g2 - g1) * intermediatePercentage),
                           blue: CGFloat(b1 + (b2 - b1) * intermediatePercentage),
                           alpha: CGFloat(a1 + (a2 - a1) * intermediatePercentage))
        }
    }
}
您可以使用它在两种或多种颜色之间获得中间颜色:

let color = [.green, .yellow, .red].intermediate(percentage: 70)
Swift 5.3 获取两种颜色之间的n种颜色:

import UIKit

extension CGFloat {
    var getPercentageValues: [CGFloat] {
        let increment: CGFloat = 100/(self-1)
        var values = [CGFloat]()
        let last: CGFloat = 100
        var value: CGFloat = 0
        while value <= last {
            values.append(value)
            value += increment
        }
        return values
    }
}

extension UIColor {
    func toColor(_ color: UIColor, percentage: CGFloat) -> UIColor {
        let percentage = max(min(percentage, 100), 0) / 100
        switch percentage {
        case 0: return self
        case 1: return color
        default:
            var (r1, g1, b1, a1): (CGFloat, CGFloat, CGFloat, CGFloat) = (.zero, .zero, .zero, .zero)
            var (r2, g2, b2, a2): (CGFloat, CGFloat, CGFloat, CGFloat) = (.zero, .zero, .zero, .zero)
            guard self.getRed(&r1, green: &g1, blue: &b1, alpha: &a1) else { return self }
            guard color.getRed(&r2, green: &g2, blue: &b2, alpha: &a2) else { return self }
            
            return UIColor(red: CGFloat(r1 + (r2 - r1) * percentage),
                           green: CGFloat(g1 + (g2 - g1) * percentage),
                           blue: CGFloat(b1 + (b2 - b1) * percentage),
                           alpha: CGFloat(a1 + (a2 - a1) * percentage))
        }
    }
    
    func getColors(to color: UIColor, with quantity: CGFloat) -> [UIColor] { 
        quantity.getPercentageValues.map { self.toColor(color, percentage: $0 ) }
    }
}

let redColor = UIColor.red
let blueColor = UIColor.blue

print(redColor.getColors(to: blueColor, with: 10))
导入UIKit
扩展CGFloat{
var getPercentageValues:[CGFloat]{
让增量:CGFloat=100/(自1)
var值=[CGFloat]()
让最后一个:CGFloat=100
变量值:CGFloat=0
而值为UIColor{
让百分比=最大值(最小值(百分比,100),0)/100
开关百分比{
案例0:返回自我
案例1:返回颜色
违约:
var(r1,g1,b1,a1):(CGFloat,CGFloat,CGFloat,CGFloat)=(0,0,0,0)
var(r2,g2,b2,a2):(CGFloat,CGFloat,CGFloat,CGFloat)=(0
保护self.getRed(&r1,绿色:&g1,蓝色:&b1,alpha:&a1)else{return self}
保护色。getRed(&r2,绿色:&g2,蓝色:&b2,alpha:&a2)else{return self}
返回UIColor(红色:CGFloat(r1+(r2-r1)*百分比),
绿色:CGFloat(g1+(g2-g1)*百分比),
蓝色:CGFloat(b1+(b2-b1)*百分比),
α:CGFloat(a1+(a2-a1)*百分比)
}
}
func getColors(to color:UIColor,数量为CGFloat)->[UIColor]{
quantity.getPercentageValues.map{self.toColor(颜色,百分比:$0)}
}
}
让redColor=UIColor.red
让blueColor=UIColor.blue
打印(redColor.getColors(to:blueColor,with:10))
结果

我可以为这一点提供一个客观的c版本吗?这正是我想要的
import UIKit

extension CGFloat {
    var getPercentageValues: [CGFloat] {
        let increment: CGFloat = 100/(self-1)
        var values = [CGFloat]()
        let last: CGFloat = 100
        var value: CGFloat = 0
        while value <= last {
            values.append(value)
            value += increment
        }
        return values
    }
}

extension UIColor {
    func toColor(_ color: UIColor, percentage: CGFloat) -> UIColor {
        let percentage = max(min(percentage, 100), 0) / 100
        switch percentage {
        case 0: return self
        case 1: return color
        default:
            var (r1, g1, b1, a1): (CGFloat, CGFloat, CGFloat, CGFloat) = (.zero, .zero, .zero, .zero)
            var (r2, g2, b2, a2): (CGFloat, CGFloat, CGFloat, CGFloat) = (.zero, .zero, .zero, .zero)
            guard self.getRed(&r1, green: &g1, blue: &b1, alpha: &a1) else { return self }
            guard color.getRed(&r2, green: &g2, blue: &b2, alpha: &a2) else { return self }
            
            return UIColor(red: CGFloat(r1 + (r2 - r1) * percentage),
                           green: CGFloat(g1 + (g2 - g1) * percentage),
                           blue: CGFloat(b1 + (b2 - b1) * percentage),
                           alpha: CGFloat(a1 + (a2 - a1) * percentage))
        }
    }
    
    func getColors(to color: UIColor, with quantity: CGFloat) -> [UIColor] { 
        quantity.getPercentageValues.map { self.toColor(color, percentage: $0 ) }
    }
}

let redColor = UIColor.red
let blueColor = UIColor.blue

print(redColor.getColors(to: blueColor, with: 10))