看了好多天CoreAnimation文档,CALayer可以设置background是CGColor。而CGColor可以通过CGPatternRef获取,这样就可以让背景颜色多姿多彩了,但是当时只是看了下这块,没有详细探讨。今天想把这块详细探讨下。为以后再看相关资料就一幕了然。
api 初始化
CG_EXTERN CGPatternRef __nullable CGPatternCreate(void * __nullable info,
CGRect bounds, CGAffineTransform matrix, CGFloat xStep, CGFloat yStep,
CGPatternTiling tiling, bool isColored,
const CGPatternCallbacks * cg_nullable callbacks)
/*填充模式
info://传递给callback的参数
bounds:需要铺瓷砖大小
matrix:形变
xStep:瓷砖横向间距
yStep:瓷砖纵向间距
tiling:贴砖的方法(瓷砖摆放的方式)
isClored:绘制的瓷砖是否已经指定了颜色(对于无颜色瓷砖此处指定位false)
callbacks:回调函数
*/
模型图
基本使用
#define H_PATTERN_SIZE 16
#define V_PATTERN_SIZE 18
void MyDrawColoredPattern (void *info, CGContextRef myContext)
{
CGFloat subunit = 5;
CGRect myRect1 = {{0,0}, {subunit, subunit}},
myRect2 = {{subunit, subunit}, {subunit, subunit}},
myRect3 = {{0,subunit}, {subunit, subunit}},
myRect4 = {{subunit,0}, {subunit, subunit}};
CGContextSetRGBFillColor (myContext, 0, 0, 1, 0.5);
CGContextFillRect (myContext, myRect1);
CGContextSetRGBFillColor (myContext, 1, 0, 0, 0.5);
CGContextFillRect (myContext, myRect2);
CGContextSetRGBFillColor (myContext, 0, 1, 0, 0.5);
CGContextFillRect (myContext, myRect3);
CGContextSetRGBFillColor (myContext, .5, 0, .5, 0.5);
CGContextFillRect (myContext, myRect4);
}
- (void)drawRect:(CGRect)rect {
CGContextRef myContext = UIGraphicsGetCurrentContext();
CGPatternRef pattern;
CGColorSpaceRef patternSpace;
CGFloat alpha = 1;
static const CGPatternCallbacks callbacks = {0,
&MyDrawColoredPattern,
NULL};
CGContextSaveGState (myContext);
patternSpace = CGColorSpaceCreatePattern (NULL);
CGContextSetFillColorSpace (myContext, patternSpace);
CGColorSpaceRelease (patternSpace);
pattern = CGPatternCreate (NULL,
CGRectMake (0, 0, H_PATTERN_SIZE, V_PATTERN_SIZE),
CGAffineTransformMake (1, 0, 0, 1, 0, 0),
H_PATTERN_SIZE,
V_PATTERN_SIZE,
kCGPatternTilingConstantSpacing,
true,
&callbacks);
CGContextSetFillPattern (myContext, pattern, &alpha);
CGPatternRelease (pattern);
CGContextFillRect (myContext, rect);
CGContextRestoreGState (myContext);
}
概述
patterns是重复绘制到图形上下文的一系列绘图操作。你可以把他当做颜色的一种吧。当我们是使用patterns绘制时,Quartz将页面划分为一组pattern cell,每个cell具有图案图像的大小,并使用您提供的回调绘制每个cell。
cell 就是上图的红色的方块
模式剖析
cell是pattern的基本组件。上图的cell是下图所示。(黑色矩形不是图案的一部分,他是用来显示一个cell的bound的)
这个cell的大小包含四个彩色矩形就面积和矩形上方和右侧的空间。若果将cell排列开来就是下图的样子。
我们可以指定quaztz在水平或者垂直方向上将每个cell起点和下一个图案cell的起点相距多远。下图就是图例
这里需要注意,要是我们设置间距太短,会导致pattern 的cell重叠
当我们绘制cell的时候,quzrtz使用pattern的空间作为坐标系,pattern的space是一个抽象空间。他通过创建我们指定的transformation matrix 映射到默认的用户空间。
pattern空间与用户空间是分开的。不管当transformation matrix的状态如何,untransformed pattern space映射到基本用户空间(未转换的untransform)。当将transformation应用于pattern 的spcace时,quzartz仅将transformation应用于pattern 的space。这里就是说要是我们给pattern设置了transformation,只会影响pattern的转换,不会对其他的颜色空间产生影响。
pattern的坐标系模式和graphics context(图形上下文)一样的。默认情况下,Quartz使用坐标系,其中正x值表示向右的位移,正y值表示向上的位移。然而,UIKit创建的图形上下文使用不同的约定,其中正y值指示向下位移。通常,两个坐标系之间转换只是通过将transform来改变就可以了,但在这种情况下,Quartz还修改pattern space 来与之匹配。
如果不想用quartz来pattern cell,可以指定标准矩阵。但是,可以通过提供转换矩阵来实现有趣的效果。
下面可以实现的效果
CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformScale(transform, 1.0, 5.0);
pattern = CGPatternCreate (NULL,
CGRectMake (0, 0, H_PATTERN_SIZE, V_PATTERN_SIZE),
transform,
H_PATTERN_SIZE,
V_PATTERN_SIZE,
kCGPatternTilingConstantSpacing,
false,
&callbacks);
CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformScale(transform, 1.0, 5.0);
transform = CGAffineTransformRotate(transform, M_PI/4);
pattern = CGPatternCreate (NULL,
CGRectMake (0, 0, H_PATTERN_SIZE, V_PATTERN_SIZE),
transform,
H_PATTERN_SIZE,
V_PATTERN_SIZE,
kCGPatternTilingConstantSpacing,
false,
&callbacks);
Colored Patterns 和 Stencil (Uncolored) Patterns
Colored Patterns 自身带有颜色。colored pattern通过改变cell的着色达到pattern颜色的改变,这样就失去了该模式的意义了。一个Scottish tartan 格子是colored patterns的一个例子。colored Pattern中的颜色只是pattern cell创建的一部分,而不是图案绘制过程中的一部分。
Stencil (Uncolored) Patterns 仅根据形状来定义,因此可以认为是模板图案、没有着色的图案或者是layer的 mask。下图展示的是相同cell的重复排列。cell本身仅是一个形状,一个填充的五角星。单pattern cell被定义时,没有任何颜色相关。颜色被指定为parttern绘制过程的一部分,而不是patterncell 创建的一部分。
我们可以通过Quartz 2D 创建上述的两种模式pattern。
Tiling (拼接)
Tiling 是将pattern cell绘制到页面的过程中的一部分。当quartz 渲染一个pattern到设备时,quartz可能需要调整pattern来适配设备空间。也就是说,当呈现给设备的时候,作为被定义在用user space的pattern cell可能不匹配设备像素,因为user space和设备的像素之间可能有差异。
因此,quartz 提供三种选项,在必要的时候来调整pattern。
- pattern 通过调整pattern cell之间的间距为代价来适配pattern。这种无失真。kCGPatternTilingNoDistortion
- cell之间以稍微扭曲模式来适配pattern。这种模式恒定间距的最小失真。kCGPatternTilingConstantSpacingMinimalDistortion
- cell之间的间距以牺牲pattern cell的扭曲成都来获取快速平铺。这被称为恒定间距。kCGPatternTilingConstantSpacing
如何使用pattern
pattern类似简单的颜色,我们需要设置一个fill或者stroke pattern,然后调用绘制函数。Quartz用设置的pattern进行绘制。例如,绘制纯色的fill 矩形,首先调用一个函数,比如CGContextSetFill,来色值fill颜色,然后调用函数CGContextFillRect 将我们指定的pattern颜色进行绘制。若用pattern 绘制,必须调用函数CGContextSetFillPattern函数来设置pattern。然后调用CGContextFillRect函数用我们指定的pattern进行填充fill 矩形。用color和pattern绘制的不同点在于我们必须定义pattern。我们需要提供pattern或者color信息给函数CGContextSetFillPattern。下面我们会看到在Colored Patterns 和 Painting Stencil Patterns模式下如何创建设置和绘制patterns
这里是quartz在幕后如何使用我们提供的pattern绘制的例子。当我们用pattern fill或者stroke时,quartz在概念下将执行以下任务来绘制pattern cell:
- 1.保存graphics 的状态 。
- 2.将当前的矩阵转换为pattern cell的原点
- 3.将CTM与pattern matrix级联
- 4.剪切cell的边界矩形
- 5.调用绘制函数绘制cell
- 6.绘制graphics 的状态
Quartz 为我们处理平铺的事情,重复的将cell渲染到绘图空间,直到整个空间被绘制。我们可以用pattern 进行fill或者stroke。pattern cell可以指定任意大小。如果我们想看到pattern,我们必须确保pattern适合绘制空间。例如:如果我们的pattern cell是个8个单位乘以10个单位的大小,但是如果我们用带有两个单位的宽度的pattern来stroke 一条线,那么pattern 的cell 将被裁剪,因为它是10个单位宽。(线的宽度没有pattern的宽度宽)在这种模式下,就可能导致无法识别该模式。
绘制 Colored Patterns
五步完成绘制Colored Patterns
- 1.写一个回调函数
- 2.设置colorPattern颜色空间
- 3.设置Colored Patterns 的pattern
- 4.指定Colored Patterns fill或者stoke pattern
- 5.用 Colored Patterns进行绘制
最开始的例子就是官方demo啦。
#define H_PATTERN_SIZE 16
#define V_PATTERN_SIZE 18
void MyDrawColoredPattern (void *info, CGContextRef myContext)
{
CGFloat subunit = 5;
CGRect myRect1 = {{0,0}, {subunit, subunit}},
myRect2 = {{subunit, subunit}, {subunit, subunit}},
myRect3 = {{0,subunit}, {subunit, subunit}},
myRect4 = {{subunit,0}, {subunit, subunit}};
CGContextSetRGBFillColor (myContext, 0, 0, 1, 0.5);
CGContextFillRect (myContext, myRect1);
CGContextSetRGBFillColor (myContext, 1, 0, 0, 0.5);
CGContextFillRect (myContext, myRect2);
CGContextSetRGBFillColor (myContext, 0, 1, 0, 0.5);
CGContextFillRect (myContext, myRect3);
CGContextSetRGBFillColor (myContext, .5, 0, .5, 0.5);
CGContextFillRect (myContext, myRect4);
}
- (void)drawRect:(CGRect)rect {
CGContextRef myContext = UIGraphicsGetCurrentContext();
CGPatternRef pattern;// 1
CGColorSpaceRef patternSpace;// 2
CGFloat alpha = 1,// 3
width, height;// 4
static const CGPatternCallbacks callbacks = {0, // 5
&MyDrawColoredPattern,
NULL};
CGContextSaveGState (myContext);
patternSpace = CGColorSpaceCreatePattern (NULL);// 6
CGContextSetFillColorSpace (myContext, patternSpace);// 7
CGColorSpaceRelease (patternSpace);// 8
pattern = CGPatternCreate (NULL, // 9
CGRectMake (0, 0, 300, 300),// 10
CGAffineTransformMake (1, 0, 0, 1, 0, 0),// 11
H_PATTERN_SIZE, // 12
V_PATTERN_SIZE, // 13
kCGPatternTilingConstantSpacing,// 14
true, // 15
&callbacks);// 16
CGContextSetFillPattern (myContext, pattern, &alpha);// 17
CGPatternRelease (pattern);// 18
CGContextFillRect (myContext, rect);// 19
CGContextRestoreGState (myContext);
}
具体讲解
- 1.声明CGPatternRef对象。
- 2.声明一个CGColorSpaceRef 对象
- 3.声明alpha通道,并且将其设置为1,并且指定模式的不透明度为1.
- 4.定义宽高。
- 5.声明生成CGPatternRef对象所需要的callback结构体
- 6.创建CGColorSpaceRef对象,基色空间设置为null。在绘制colored pattern的时候,改图案会调用自身提供的颜色。
- 7.将pattern 的space添加到fill颜色空间中
- 8.释放pattern 的space
- 9.创建pattern (相当于获取一个color)
- 10.指定pattern cell的需要绘制的大小
- 11.通过转换矩阵将pattern的space转换到context使用的颜色空间
- 12.cell的width
- 13.cell的高度
- 14.告诉quartz 如何渲染pattern
- 15.指定pattern是colored pattern
- 16.指定回调函数
- 17.给context 设定fill pattern
- 18.释放pattern对象
- 19.填充对象
绘制 Stencil Patterns
步骤如下:
- 1.写一个回调函数
- 2.设置stencil Pattern颜色空间
- 3.设置stencil Patterns 的pattern
- 4.指定stencil Patterns fill或者stoke pattern
- 5.用 stencil Patterns进行绘制
步骤和colored 一样的这里不做讲解了。我们应该看具体效果更直观了
参数配置效果
参数可以分一下几个角度来看
- CGAffineTransform matrix
- CGPatternTiling tiling
- bool isColored
- CGRect bounds
CGAffineTransform matrix
这里我们将矩阵设置成标准矩阵,缩放矩阵,旋转,平移矩阵看效果
采用colored pattern 和kCGPatternTilingNoDistortion 渲染样式。
标准矩阵
#define SizeItem 16
#define H_PATTERN_SIZE SizeItem*4
#define V_PATTERN_SIZE SizeItem*4
void MyDrawColoredPattern (void *info, CGContextRef myContext)
{
CGContextSetRGBFillColor (myContext, 0, 0, 1, 1);
CGContextAddArc(myContext, SizeItem, SizeItem, SizeItem, 0, M_PI*2, YES);
CGContextEOFillPath(myContext);
CGContextSetRGBFillColor (myContext, 1, 0, 0, 1);
CGContextAddArc(myContext, SizeItem*3, SizeItem*3, SizeItem, 0, M_PI*2, YES);
CGContextEOFillPath(myContext);
CGContextSetRGBStrokeColor(myContext, 1, 0, 1, 1);
CGContextStrokeRect(myContext, CGRectMake(0, 0, H_PATTERN_SIZE, V_PATTERN_SIZE));
}
- (void)drawRect:(CGRect)rect {
CGContextRef myContext = UIGraphicsGetCurrentContext();
CGPatternRef pattern;
CGColorSpaceRef patternSpace;
CGFloat alpha = 1;
static const CGPatternCallbacks callbacks = {0,
&MyDrawColoredPattern,
NULL};
CGContextSaveGState (myContext);
patternSpace = CGColorSpaceCreatePattern (NULL);
CGContextSetFillColorSpace (myContext, patternSpace);
CGColorSpaceRelease (patternSpace);
pattern = CGPatternCreate (NULL,
CGRectMake (0, 0, 160, 160),
CGAffineTransformIdentity,
H_PATTERN_SIZE,
V_PATTERN_SIZE,
kCGPatternTilingNoDistortion,
true,
&callbacks);
CGContextSetFillPattern (myContext, pattern, &alpha);
CGPatternRelease (pattern);
CGContextFillRect (myContext, rect);
CGContextRestoreGState (myContext);
}
旋转
#define SizeItem 16
#define H_PATTERN_SIZE SizeItem*4
#define V_PATTERN_SIZE SizeItem*4
void MyDrawColoredPattern (void *info, CGContextRef myContext)
{
CGContextSetRGBFillColor (myContext, 0, 0, 1, 1);
CGContextAddArc(myContext, SizeItem, SizeItem, SizeItem, 0, M_PI*2, YES);
CGContextEOFillPath(myContext);
CGContextSetRGBFillColor (myContext, 1, 0, 0, 1);
CGContextAddArc(myContext, SizeItem*3, SizeItem*3, SizeItem, 0, M_PI*2, YES);
CGContextEOFillPath(myContext);
CGContextSetRGBStrokeColor(myContext, 1, 0, 1, 1);
CGContextStrokeRect(myContext, CGRectMake(0, 0, H_PATTERN_SIZE, V_PATTERN_SIZE));
}
- (void)drawRect:(CGRect)rect {
CGContextRef myContext = UIGraphicsGetCurrentContext();
CGPatternRef pattern;
CGColorSpaceRef patternSpace;
CGFloat alpha = 1;
static const CGPatternCallbacks callbacks = {0,
&MyDrawColoredPattern,
NULL};
CGContextSaveGState (myContext);
patternSpace = CGColorSpaceCreatePattern (NULL);
CGContextSetFillColorSpace (myContext, patternSpace);
CGColorSpaceRelease (patternSpace);
CGAffineTransform transform =CGAffineTransformRotate(CGAffineTransformIdentity, M_PI/4);
pattern = CGPatternCreate (NULL,
CGRectMake (0, 0, 160, 160),
transform,
H_PATTERN_SIZE,
V_PATTERN_SIZE,
kCGPatternTilingNoDistortion,
true,
&callbacks);
CGContextSetFillPattern (myContext, pattern, &alpha);
CGPatternRelease (pattern);
CGContextFillRect (myContext, rect);
CGContextRestoreGState (myContext);
}
缩放
#define SizeItem 16
#define H_PATTERN_SIZE SizeItem*4
#define V_PATTERN_SIZE SizeItem*4
void MyDrawColoredPattern (void *info, CGContextRef myContext)
{
CGContextSetRGBFillColor (myContext, 0, 0, 1, 1);
CGContextAddArc(myContext, SizeItem, SizeItem, SizeItem, 0, M_PI*2, YES);
CGContextEOFillPath(myContext);
CGContextSetRGBFillColor (myContext, 1, 0, 0, 1);
CGContextAddArc(myContext, SizeItem*3, SizeItem*3, SizeItem, 0, M_PI*2, YES);
CGContextEOFillPath(myContext);
CGContextSetRGBStrokeColor(myContext, 1, 0, 1, 1);
CGContextStrokeRect(myContext, CGRectMake(0, 0, H_PATTERN_SIZE, V_PATTERN_SIZE));
}
- (void)drawRect:(CGRect)rect {
CGContextRef myContext = UIGraphicsGetCurrentContext();
CGPatternRef pattern;
CGColorSpaceRef patternSpace;
CGFloat alpha = 1;
static const CGPatternCallbacks callbacks = {0,
&MyDrawColoredPattern,
NULL};
CGContextSaveGState (myContext);
patternSpace = CGColorSpaceCreatePattern (NULL);
CGContextSetFillColorSpace (myContext, patternSpace);
CGColorSpaceRelease (patternSpace);
CGAffineTransform transform= CGAffineTransformScale(CGAffineTransformIdentity, 0.5, 0.5);
pattern = CGPatternCreate (NULL,
CGRectMake (0, 0, 160, 160),
transform,
H_PATTERN_SIZE,
V_PATTERN_SIZE,
kCGPatternTilingNoDistortion,
true,
&callbacks);
CGContextSetFillPattern (myContext, pattern, &alpha);
CGPatternRelease (pattern);
CGContextFillRect (myContext, rect);
CGContextRestoreGState (myContext);
}
平移
//
// PatternLearningView.m
// CGPatternLearning
//
// Created by 温杰 on 2018/10/8.
// Copyright © 2018年 温杰. All rights reserved.
//
#import "PatternLearningView.h"
@implementation PatternLearningView
#define SizeItem 16
#define H_PATTERN_SIZE SizeItem*4
#define V_PATTERN_SIZE SizeItem*4
void MyDrawColoredPattern (void *info, CGContextRef myContext)
{
CGContextSetRGBFillColor (myContext, 0, 0, 1, 1);
CGContextAddArc(myContext, SizeItem, SizeItem, SizeItem, 0, M_PI*2, YES);
CGContextEOFillPath(myContext);
CGContextSetRGBFillColor (myContext, 1, 0, 0, 1);
CGContextAddArc(myContext, SizeItem*3, SizeItem*3, SizeItem, 0, M_PI*2, YES);
CGContextEOFillPath(myContext);
CGContextSetRGBStrokeColor(myContext, 1, 0, 1, 1);
CGContextStrokeRect(myContext, CGRectMake(0, 0, H_PATTERN_SIZE, V_PATTERN_SIZE));
}
- (void)drawRect:(CGRect)rect {
CGContextRef myContext = UIGraphicsGetCurrentContext();
CGPatternRef pattern;
CGColorSpaceRef patternSpace;
CGFloat alpha = 1;
static const CGPatternCallbacks callbacks = {0,
&MyDrawColoredPattern,
NULL};
CGContextSaveGState (myContext);
patternSpace = CGColorSpaceCreatePattern (NULL);
CGContextSetFillColorSpace (myContext, patternSpace);
CGColorSpaceRelease (patternSpace);
CGAffineTransform transform= CGAffineTransformTranslate(CGAffineTransformIdentity,SizeItem , SizeItem);
pattern = CGPatternCreate (NULL,
CGRectMake (0, 0, 160, 160),
transform,
H_PATTERN_SIZE,
V_PATTERN_SIZE,
kCGPatternTilingNoDistortion,
true,
&callbacks);
CGContextSetFillPattern (myContext, pattern, &alpha);
CGPatternRelease (pattern);
CGContextFillRect (myContext, rect);
CGContextRestoreGState (myContext);
}
CGPatternTiling tiling
CGPatternTiling 有三种模式。具体看看有啥影响
不过我试了三种模式,没发现有啥区别,可能与具体渲染有关系吧。有知道的大神可以提醒下。
bool isColored
这里我们举例官方demo
Colored pattern
#define PSIZE 16
void MyDrawColoredPattern (void *info, CGContextRef myContext)
{
int k;
double r, theta;
r = 0.8 * PSIZE / 2;
theta = 2 * M_PI * (2.0 / 5.0); // 144 degrees
CGContextTranslateCTM (myContext, PSIZE/2, PSIZE/2);
CGContextMoveToPoint(myContext, 0, r);
for (k = 1; k < 5; k++) {
CGContextAddLineToPoint (myContext,
r * sin(k * theta),
r * cos(k * theta));
}
CGContextClosePath(myContext);
CGContextStrokePath(myContext);
}
- (void)drawRect:(CGRect)rect {
CGContextRef myContext = UIGraphicsGetCurrentContext();
CGPatternRef pattern;
CGColorSpaceRef baseSpace;
CGColorSpaceRef patternSpace;
static const CGFloat color[4] = { 1, 0, 0, 1 };// 1
static const CGPatternCallbacks callbacks = {0, &MyDrawColoredPattern, NULL};// 2
baseSpace = CGColorSpaceCreateDeviceRGB ();// 3
patternSpace = CGColorSpaceCreatePattern (baseSpace);// 4
CGContextSetFillColorSpace (myContext, patternSpace);// 5
CGColorSpaceRelease (patternSpace);
CGColorSpaceRelease (baseSpace);
pattern = CGPatternCreate(NULL, CGRectMake(0, 0, PSIZE, PSIZE),// 6
CGAffineTransformIdentity, PSIZE, PSIZE,
kCGPatternTilingConstantSpacing,
true, &callbacks);
CGContextSetFillPattern (myContext, pattern, color);// 7
CGPatternRelease (pattern);// 8
CGContextFillRect (myContext,CGRectMake (0,0,PSIZE*20,PSIZE*20));
}
看上图我们的五角星是黑色的默认颜色,没有更改。
其实colored pattern调用CGColorSpaceCreatePattern 需要传入null,可以不传参数。
Stencil pattern
#define PSIZE 16
void MyDrawColoredPattern (void *info, CGContextRef myContext)
{
int k;
double r, theta;
r = 0.8 * PSIZE / 2;
theta = 2 * M_PI * (2.0 / 5.0); // 144 degrees
CGContextTranslateCTM (myContext, PSIZE/2, PSIZE/2);
CGContextMoveToPoint(myContext, 0, r);
for (k = 1; k < 5; k++) {
CGContextAddLineToPoint (myContext,
r * sin(k * theta),
r * cos(k * theta));
}
CGContextClosePath(myContext);
CGContextStrokePath(myContext);
}
- (void)drawRect:(CGRect)rect {
CGContextRef myContext = UIGraphicsGetCurrentContext();
CGPatternRef pattern;
CGColorSpaceRef baseSpace;
CGColorSpaceRef patternSpace;
static const CGFloat color[4] = { 1, 0, 0, 1 };// 1
static const CGPatternCallbacks callbacks = {0, &MyDrawColoredPattern, NULL};// 2
baseSpace = CGColorSpaceCreateDeviceRGB ();// 3
patternSpace = CGColorSpaceCreatePattern (baseSpace);// 4
CGContextSetFillColorSpace (myContext, patternSpace);// 5
CGColorSpaceRelease (patternSpace);
CGColorSpaceRelease (baseSpace);
pattern = CGPatternCreate(NULL, CGRectMake(0, 0, PSIZE, PSIZE),// 6
CGAffineTransformIdentity, PSIZE, PSIZE,
kCGPatternTilingConstantSpacing,
false, &callbacks);
CGContextSetFillPattern (myContext, pattern, color);// 7
CGPatternRelease (pattern);// 8
CGContextFillRect (myContext,CGRectMake (0,0,PSIZE*20,PSIZE*20));
}
这里我们只是简单的将colored pattern 代码中的true 改成了false ,我们发现五角星变成了红色。
因此,这里我们就名了colored 和 Stencil pattern的真正区别了。
colored pattern 不会使用当前空间的任何颜色,需要我们指定颜色
Stencil pattern 使用当前颜色空间中设置好的颜色。我们不需要在指定颜色。只是不需要指定颜色,当然也可以设置颜色了。
下图只是简单的在callback回调函数中设置线颜色为蓝色,最终就渲染成蓝色的了
#define PSIZE 16
void MyDrawColoredPattern (void *info, CGContextRef myContext)
{
int k;
double r, theta;
r = 0.8 * PSIZE / 2;
theta = 2 * M_PI * (2.0 / 5.0); // 144 degrees
CGContextTranslateCTM (myContext, PSIZE/2, PSIZE/2);
CGContextMoveToPoint(myContext, 0, r);
for (k = 1; k < 5; k++) {
CGContextAddLineToPoint (myContext,
r * sin(k * theta),
r * cos(k * theta));
}
CGContextClosePath(myContext);
CGContextSetRGBStrokeColor(myContext, 0, 0, 1, 1.0);
CGContextStrokePath(myContext);
}
CGrect bounds
具体看例子
#define SizeItem 16
#define H_PATTERN_SIZE SizeItem*4
#define V_PATTERN_SIZE SizeItem*4
void MyDrawColoredPattern (void *info, CGContextRef myContext)
{
CGContextSetRGBFillColor (myContext, 0, 0, 1, 1);
CGContextAddArc(myContext, SizeItem, SizeItem, SizeItem, 0, M_PI*2, YES);
CGContextEOFillPath(myContext);
CGContextSetRGBFillColor (myContext, 1, 0, 0, 1);
CGContextAddArc(myContext, SizeItem*3, SizeItem*3, SizeItem, 0, M_PI*2, YES);
CGContextEOFillPath(myContext);
CGContextSetRGBStrokeColor(myContext, 1, 0, 1, 1);
CGContextStrokeRect(myContext, CGRectMake(0, 0, H_PATTERN_SIZE, V_PATTERN_SIZE));
}
- (void)drawRect:(CGRect)rect {
CGContextRef myContext = UIGraphicsGetCurrentContext();
CGPatternRef pattern;
CGColorSpaceRef patternSpace;
CGFloat alpha = 1;
static const CGPatternCallbacks callbacks = {0,
&MyDrawColoredPattern,
NULL};
CGContextSaveGState (myContext);
patternSpace = CGColorSpaceCreatePattern (NULL);
CGContextSetFillColorSpace (myContext, patternSpace);
CGColorSpaceRelease (patternSpace);
CGAffineTransform transform= CGAffineTransformIdentity;
pattern = CGPatternCreate (NULL,
CGRectMake (20, 20, H_PATTERN_SIZE, V_PATTERN_SIZE),
transform,
H_PATTERN_SIZE,
V_PATTERN_SIZE,
kCGPatternTilingNoDistortion,
true,
&callbacks);
// CGContextTranslateCTM (myContext, 20, 20);
CGContextSetFillPattern (myContext, pattern, &alpha);
CGPatternRelease (pattern);
CGContextFillRect (myContext, rect);
CGContextRestoreGState (myContext);
}
bound的origin 起作用。相当于tiling之间的间隔。origin起作用必须是bound的size必须大于cell的大小才行。
给UIView 的backgroundColor增加CGPatternRef图片
给layer 的backgroundColor 增加CGPatternRef 图片
为什么先给layer 增加呢?保证我们给layer可以增加上图片。再试UIView的backgroundColor
测试代码
void MyDrawColoredPattern (void *info, CGContextRef myContext)
{
UIImage * image = [UIImage imageNamed:@"guaguale.jpg"];
CGContextDrawImage(myContext,[UIScreen mainScreen].bounds , image.CGImage);
}
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
CALayer *layer = [CALayer layer];
[self.layer addSublayer:layer];
layer.anchorPoint = CGPointZero;
layer.bounds = self.bounds;
layer.backgroundColor=[self getBgColor];;
}
return self;
}
-(CGColorRef)getBgColor{
CGPatternRef pattern;
CGColorSpaceRef patternSpace;
CGFloat alpha = 1;
static const CGPatternCallbacks callbacks = {0,
&MyDrawColoredPattern,
NULL};
CGColorSpaceRef patcolor=CGColorSpaceCreateDeviceRGB();
patternSpace = CGColorSpaceCreatePattern (NULL);
pattern = CGPatternCreate (NULL,
self.bounds,
CGAffineTransformMake (1, 0, 0, 1, 0, 0),
self.bounds.size.width,
self.bounds.size.height,
kCGPatternTilingConstantSpacing,
true,
&callbacks);
CGColorRef color = CGColorCreateWithPattern(patternSpace, pattern, &alpha);
CGPatternRelease(pattern);
CGColorSpaceRelease(patternSpace);
return color;
}
测试结果
给layer增加背景颜色是图片是没有问题的。
给UIView的layer设置backgroundColor是pattern
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
UIView * view = [[PatternLearningView alloc]initWithFrame:self.view.bounds];
// view.backgroundColor = [UIColor colorWithCGColor:[self getBgColor]];
[self.view addSubview:view];
view.layer.backgroundColor = [self getBgColor];
}
-(CGColorRef)getBgColor{
CGPatternRef pattern;
CGColorSpaceRef patternSpace;
CGFloat alpha = 1;
static const CGPatternCallbacks callbacks = {0,
&MyDrawColoredPattern1,
NULL};
patternSpace = CGColorSpaceCreatePattern (NULL);
pattern = CGPatternCreate (NULL,
self.view.bounds,
CGAffineTransformMake (1, 0, 0, 1, 0, 0),
self.view.bounds.size.width,
self.view.bounds.size.height,
kCGPatternTilingConstantSpacing,
true,
&callbacks);
CGColorRef color = CGColorCreateWithPattern(patternSpace, pattern, &alpha);
CGPatternRelease(pattern);
CGColorSpaceRelease(patternSpace);
return color;
}
void MyDrawColoredPattern1 (void *info, CGContextRef myContext)
{
UIImage * image = [UIImage imageNamed:@"guaguale.jpg"];
CGContextDrawImage(myContext,[UIScreen mainScreen].bounds , image.CGImage);
}
结果如图
给UIView的backgroundColor设置pattern color
这里肯定也是没问题的,UIview的backgroundColor 和layer的backgroundColor 之间的关系只是映射而已。
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
UIView * view = [[PatternLearningView alloc]initWithFrame:self.view.bounds];
view.backgroundColor = [UIColor colorWithCGColor:[self getBgColor]];
[self.view addSubview:view];
}
-(CGColorRef)getBgColor{
CGPatternRef pattern;
CGColorSpaceRef patternSpace;
CGFloat alpha = 1;
static const CGPatternCallbacks callbacks = {0,
&MyDrawColoredPattern1,
NULL};
patternSpace = CGColorSpaceCreatePattern (NULL);
pattern = CGPatternCreate (NULL,
self.view.bounds,
CGAffineTransformMake (1, 0, 0, 1, 0, 0),
self.view.bounds.size.width,
self.view.bounds.size.height,
kCGPatternTilingConstantSpacing,
true,
&callbacks);
CGColorRef color = CGColorCreateWithPattern(patternSpace, pattern, &alpha);
CGPatternRelease(pattern);
CGColorSpaceRelease(patternSpace);
return color;
}
void MyDrawColoredPattern1 (void *info, CGContextRef myContext)
{
UIImage * image = [UIImage imageNamed:@"guaguale.jpg"];
CGContextDrawImage(myContext,[UIScreen mainScreen].bounds , image.CGImage);
}
测试结果
但是绘制的图片是反着的。这里我们需要设置下pattern 的transform。这里就不做了。图形变换经常搞,这点知识才搞起来就没劲啦。
app 文档