看了好多天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。這里就不做了。圖形變換經常搞,這點知識才搞起來就沒勁啦。