如何使用颜色划分创建渐变效果?

Posted

技术标签:

【中文标题】如何使用颜色划分创建渐变效果?【英文标题】:How can I create a gradient effect using color divisions? 【发布时间】:2017-09-01 16:05:01 【问题描述】:

我正在尝试创建一个表格视图(自定义类不是 UITableView),其结果具有渐变效果,如下图示例所示:

我尝试了什么:

    我成功地为每个表格单元格添加了正确的渐变作为背景,但我需要它是每个标签文本的颜色,而不是每个单元格的背景。 Question。 (我问过这个。)

尝试失败:

    创建自定义渐变图像并将其作为 colorWithPatternImage: 添加到每个标签,但由于渐变是一个,因此每个单元格看起来都相同。 Question。

尝试失败:

最后一件事:

假设你有两种颜色,color1 和 color2。通过混合这些颜色可以产生渐变。在上图中,color1 = 紫色,color2 = 橙色。根据结果​​的数量将渐变划分为多个部分,然后找到每个部分的平均颜色并将其用作每个对应结果的文本颜色,就可以轻松创建渐变效果。

例如:

5 个结果 = 5 个部门。

division1 = 紫色 division2 = 紫色较少,橙色较多 division3 = 等紫色,等橙色 division4 = 紫色最少,橙色最多 division5 = 橙色

结果没有那么详细,因为每个文本都是纯色的,但当文本很小时同样令人印象深刻:

问题是,对于像这样的两种颜色:

紫色:128.0、0.0、255.0

橙色:255.0、128.0、0.0

你如何把它分成 5 个部分并求每个部分的平均值?

我可以使用 pixelmator 中的吸管工具来做到这一点,但前提是我知道固定数量的结果,不能使用 6 个结果。

我无法用数学来解决它,我不知道从哪里开始。

有什么想法吗?

【问题讨论】:

【参考方案1】:

您可以对颜色的 rgb 值使用数学运算。

要获取 rgb 值,您可以在 UIColor 上使用 getRed:green:blue:alpha 方法。然后你所要做的就是根据你需要多少部分来平均颜色。

这是一个函数,它应该根据开始和结束颜色以及您需要的分割数返回一个颜色数组。

解决方案

func divideColors(firstColor: UIColor, secondColor: UIColor, sections: Int) -> [UIColor] 

    // get rgb values from the colors
    var firstRed: CGFloat = 0; var firstGreen: CGFloat = 0; var firstBlue: CGFloat = 0; var firstAlpha: CGFloat = 0;
    firstColor.getRed(&firstRed, green: &firstGreen, blue: &firstBlue, alpha: &firstAlpha)
    var secondRed: CGFloat = 0; var secondGreen: CGFloat = 0; var secondBlue: CGFloat = 0; var secondAlpha: CGFloat = 0;
    secondColor.getRed(&secondRed, green: &secondGreen, blue: &secondBlue, alpha: &secondAlpha)

    // function to mix the colors
    func mix(_ first: CGFloat, _ second: CGFloat, ratio: CGFloat) -> CGFloat  return first + ratio * (second - first) 

    // variable setup
    var colors = [UIColor]()
    let ratioPerSection = 1.0 / CGFloat(sections)

    // mix the colors for each section
    for section in 0 ..< sections 
        let newRed = mix(firstRed, secondRed, ratio: ratioPerSection * CGFloat(section))
        let newGreen = mix(firstGreen, secondGreen, ratio: ratioPerSection * CGFloat(section))
        let newBlue = mix(firstBlue, secondBlue, ratio: ratioPerSection * CGFloat(section))
        let newAlpha = mix(firstAlpha, secondAlpha, ratio: ratioPerSection * CGFloat(section))
        let newColor = UIColor(red: newRed, green: newGreen, blue: newBlue, alpha: newAlpha)
        colors.append(newColor)
    

    return colors


您的问题被标记为 Objective-C,但将上面的 Swift 代码转换为 Objective-C 应该很容易,因为您将使用相同的 UIColor API。

这是一些测试上述功能的代码(非常适合 Swift 游乐场)。

测试代码

let sections = 5
let view = UIView(frame: CGRect(x: 0, y: 0, width: 250, height: 50))
for (index, color) in divideColors(firstColor: UIColor.purple, secondColor: UIColor.orange, sections: sections).enumerated() 
    let v = UIView(frame: CGRect(x: CGFloat(index) * 250 / CGFloat(sections), y: 0, width: 250 / CGFloat(sections), height: 50))
    v.backgroundColor = color
    view.addSubview(v)

view.backgroundColor = .white

测试结果

它也适用于任意数量的部分和不同的颜色!

【讨论】:

如果你能在 Objective-c 中发布这个。 @Vulkan 无论您使用 Swift 还是 Objective-C,API 和逻辑都是相同的。现有的 SO 答案涵盖了如何做所有这些事情(从 UIColor 获取 rgb 值、创建和修改数组等) 你是对的,但我看不懂 Swift,我读了这些:“firstColor.getRed(&firstRed, green: &firstGreen, blue: &firstBlue, alpha: &firstAlpha)”, “func mix(_ first : CGFloat, _ second: CGFloat, ratio: CGFloat) -> CGFloat return first + ratio * (second - first) "。我无法阅读它们,也无法将它们转换为 ObjC。 看起来 rgb 颜色的 Objective-C 语法非常相似:***.com/a/7852266/6658553 mix 函数是一个嵌套函数,在 Obj-C 中是做不到的。相反,只需创建一个单独的方法。下面是 Obj-C 中方法语法的解释:***.com/a/683290/6658553【参考方案2】:

所以你想要这个:

有几种方法可以实现这一点。这是一种像素完美的方法(它通过标签绘制渐变,而不是让每个标签都变成纯色)。

创建UILabel 的子类。在您的子类中,覆盖 drawTextInRect: 以绘制渐变。

让我们像这样声明子类:

IB_DESIGNABLE
@interface GradientLabel: UILabel

@property (nonatomic, weak) IBOutlet UIView *gradientCoverageView;
@property (nonatomic, strong) IBInspectable UIColor *startColor;
@property (nonatomic, strong) IBInspectable UIColor *endColor;

@end

gradientCoverageView 出口连接到覆盖整个渐变区域的视图,即覆盖所有五个标签的视图。这可能是标签的超级视图,也可能只是您设置为(不可见地)填充同一区域的隐藏视图。

startColor 设置为紫色,将endColor 设置为橙色。

我们将分三步绘制渐变填充文本(在我们的drawTextInRect: 覆盖中):

    调用super即可正常绘制文字。

    设置图形上下文混合模式kCGBlendModeSourceIn。这种混合模式告诉 Core Graphics 只在上下文已经绘制的地方绘制,并覆盖那里绘制的任何内容。因此Core Graphics 将super 绘制的文本视为掩码。

    coverage视图顶部为起点,coverage视图底部为终点绘制渐变,不是 在当前标签的顶部和底部。因此,渐变跨越整个覆盖视图,但被遮盖以仅显示在步骤 1 中绘制当前标签文本的位置。

下面是实现:

@implementation GradientLabel

- (void)drawTextInRect:(CGRect)rect 
    [super drawTextInRect:rect];

    CGContextRef gc = UIGraphicsGetCurrentContext();
    NSArray *colors = @[(__bridge id)self.startColor.CGColor, (__bridge id)self.endColor.CGColor];
    CGGradientRef gradient = CGGradientCreateWithColors(CGBitmapContextGetColorSpace(gc), (__bridge CFArrayRef)colors, NULL);

    UIView *coverageView = self.gradientCoverageView ?: self;
    CGRect coverageRect = [coverageView convertRect:coverageView.bounds toView:self];
    CGPoint startPoint = coverageRect.origin;
    CGPoint endPoint =  coverageRect.origin.x, CGRectGetMaxY(coverageRect) ;

    CGContextSaveGState(gc); 
        CGContextSetBlendMode(gc, kCGBlendModeSourceIn);
        CGContextDrawLinearGradient(gc, gradient, startPoint, endPoint, 0);
     CGContextRestoreGState(gc);

    CGGradientRelease(gradient);


@end

这是我的故事板中的布局:

对于所有五个GradientLabel 实例,我将startColor 设置为紫色,将endColor 设置为橙色,并将gradientCoverageView 出口连接到封闭的堆栈视图。

【讨论】:

感谢提供硬核方法。 :D【参考方案3】:

好吧,下面是如何在最后做纯色数学位:

如果你有 n + 1 种颜色,对于 0

color.red[m] = (purple.red * (m/n)) + (orange.red * ((n-m)/n);
color.green[m] = (purple.green * (m/n)) + (orange.green * ((n-m)/n));
color.blue[m] = (purple.blue * (m/n)) + (orange.blue * ((n-m)/n));

希望这会有所帮助。

【讨论】:

【参考方案4】:

对于 Xamarin ios C#

public static List<UIColor> DividedColors(UIColor firstColor, UIColor secondColor, int sections)

    nfloat firstRed = 0;
    nfloat firstGreen = 0;
    nfloat firstBlue = 0;
    nfloat firstAlpha = 0;
    firstColor.GetRGBA(out firstRed, out firstGreen, out firstBlue, out firstAlpha);

    nfloat secondRed = 0;
    nfloat secondGreen = 0;
    nfloat secondBlue = 0;
    nfloat secondAlpha = 0;
    secondColor.GetRGBA(out secondRed, out secondGreen, out secondBlue, out secondAlpha);

    nfloat Mix(nfloat first, nfloat second, nfloat ratio)
    
        return first + ratio * (second - first);
    

    List<UIColor> colors = new List<UIColor>();
    var ratioPerSection = 1.0f / sections;

    for (int i = 0; i < sections; i++)
    
        var newRed = Mix(firstRed, secondRed, ratioPerSection * i);
        var newGreen = Mix(firstGreen, secondGreen, ratioPerSection * i);
        var newBlue = Mix(firstBlue, secondBlue, ratioPerSection * i);
        var newAlpha = Mix(firstAlpha, secondAlpha, ratioPerSection * i);
        var newColor = new UIColor(newRed, newGreen, newBlue, newAlpha);
        colors.Add(newColor);
    

    return colors;

【讨论】:

以上是关于如何使用颜色划分创建渐变效果?的主要内容,如果未能解决你的问题,请参考以下文章

如何CSS实现网页背景三种颜色渐变效果?

iOS 绘制颜色渐变圆环 --- 值得一看

如何在 ListView 中为 TextView 的背景颜色添加渐变效果?

如何从调色板中进行颜色渐变

如何使用渐变颜色设置 UINavigationbar?

iOS 绘制颜色渐变圆环