如何使用颜色划分创建渐变效果?
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;
【讨论】:
以上是关于如何使用颜色划分创建渐变效果?的主要内容,如果未能解决你的问题,请参考以下文章