CodeV

6.11-组合渐变和纹理

贴图纹理扩展了对对象进行着色的方式,为视觉效果提供了阴影细节。 以图6-17为例。 在这些图像中,kCGBlendModeColorQuartz混合模式使您能够在背景图像上绘制渐变。 该模式从目的地上下文中拾取图像纹理(亮度值),同时保持渐变颜色的色调和饱和度。

图6-17

图6-17混合模式将渐变的颜色与底层图像的纹理结合在一起。

顶部的两个图像显示从亮(在上面)到稍微暗(在底部,亮度降低25%)的紫色渐变。 顶部图像显示原始图像源(右)以及渐变叠加(左)。 底部图像应用彩虹渐变。

代码清单6-9展示了用于创建这些图像的DrawGradientOverTexture()函数。

清单6-9用渐变叠加变换纹理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void DrawGradientOverTexture(UIBezierPath *path,
UIImage *texture, Gradient *gradient, CGFloat alpha)
{
if (!path) COMPLAIN_AND_BAIL(
@"Path cannot be nil", nil);
if (!texture) COMPLAIN_AND_BAIL(
@"Texture cannot be nil", nil);
if (!gradient) COMPLAIN_AND_BAIL(
@"Gradient cannot be nil", nil);
CGContextRef context = UIGraphicsGetCurrentContext();
if (context == NULL) COMPLAIN_AND_BAIL(
@"No context to draw into", nil);

CGRect rect = path.bounds;
PushDraw(^{
CGContextSetAlpha(context, alpha);
[path addClip];
PushLayerDraw(^{
[texture drawInRect:rect];
CGContextSetBlendMode(
context, kCGBlendModeColor);
[gradient drawTopToBottom:rect];
});
});
}

添加噪点纹理

图6-17中所示的示例使用kCGBlendModeColor混合模式将色调添加到纹理。 有时,您需要反转将纹理添加到颜色的过程。 为此,使用kCGBlendModeScreen混合模式。 图6-18显示了它的外观。 在顶部,您会看到一个正常的填充,用纯紫色的颜色创建。 中间的图像应用并且混合了噪点模式,引入微妙的纹理。 底部图像放大生成的纹理,突出显示基础变化。

这种基于噪点的技术在App Store中已经变得非常流行,用于纹理化界面颜色。 尽管作为一个“扁平”UI而众所周知,iOS 7在许多应用程序中使用微妙的纹理,如Notes和Reminders。 你可能必须仔细看看这个粒度,但它就在那里。 噪点和其他纹理提供更令人满意的感觉更自然的背景。

图6-18

图6-18使用纹理可以覆盖颜色。

屏幕混合不限于噪声,当然。 图6-19显示了混合为填充颜色的点阵图形。

图6-19

图6-19圆点图案为此背景添加纹理。

代码清单6-10提供了两个Bezier路径方法,使您能够填充一个路径。 第一个应用了使用您指定的混合模式的颜色,如图6-19所示。 第二个用颜色填充路径,然后以噪点模式进行屏幕显示,如图6-18所示。此列表显示一个简单的噪点颜色生成器。

Note

如果你(希望)对噪点认真(研究),请参考Perlin噪点常见问题解答,网址为:http://webstaff.itn.liu.se/~stegu/TNM022-2005/perlinnoiselinks/perlin-noise-math-faq.html。 Perlin噪点提供了产生相干(即,平滑变化)噪点内容的功能。

代码清单6-10在颜色上绘制纹理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// Apply color using the specified blend mode
- (void) fill: (UIColor *) fillColor
withMode: (CGBlendMode) blendMode
{
CGContextRef context = UIGraphicsGetCurrentContext();
if (context == NULL) COMPLAIN_AND_BAIL(
@"No context to draw into", nil);

PushDraw(^{
CGContextSetBlendMode(context, blendMode);
[self fill:fillColor];
});
}

// Screen noise into the fill
- (void) fillWithNoise: (UIColor *) fillColor
{
CGContextRef context = UIGraphicsGetCurrentContext();
if (context == NULL) COMPLAIN_AND_BAIL(
@"No context to draw into", nil);

[self fill:fillColor];
[self fill:[NoiseColor()
colorWithAlphaComponent:0.05f]
withMode:kCGBlendModeScreen];
}

// Generate a noise pattern color
UIColor *NoiseColor()
{
static UIImage *noise = nil;
if (noise)
return [UIColor colorWithPatternImage:noise];

srandom(time(0));

CGSize size = CGSizeMake(128, 128);
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
for (int j = 0; j < size.height; j++)
for (int i = 0; i < size.height; i++)
{
UIBezierPath *path = [UIBezierPath
bezierPathWithRect:CGRectMake(i, j, 1, 1)];
CGFloat level = ((double) random() /(double) LONG_MAX);
[path fill:[UIColor colorWithWhite:level alpha:1]];
}

noise = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

return [UIColor colorWithPatternImage:noise];
}

本文翻译自《iOS Drawing Practical UIKit Solutions》作者:Erica Sadun,翻译:Cheng Dong。如果觉得本书不错请购买支持正版:亚马逊购买传送门,本书所有源代码可在GitHub上下载。译者虽然力求做到信,达,雅,但是由于时间仓促加之译者水平十分有限,文中难免会出现不正确,不准确,词不达意,难于理解的地方,还望各位批评指正,共同进步,谢谢。转载请注明出处。