CGPatternRef 學習

看了好多天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的起點相距多遠。下圖就是圖例


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 文檔

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,527評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,687評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,640評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,957評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,682評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,011評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,009評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,183評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,714評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,435評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,665評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,148評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,838評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,251評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,588評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,379評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,627評論 2 380

推薦閱讀更多精彩內容

  • 關于夏天,記憶里似乎都和幸福相關,但為什么世界變得那么陌生而可怕了,夏天并沒有變不是嗎? 童年時光是有神力存在的,...
    知寒XY閱讀 236評論 0 0
  • 今天又考試了,考完了………也完了……傷心死了
    潘多拉coco閱讀 137評論 0 0
  • 感賞兒子考完后老師獎勵他一大包零食、聽兒子說是老師規定的如果作文寫400字的都有、我榮興兒子也得到了。 感賞兒子回...
    虹毅閱讀 220評論 0 3