Quartz2D以及drawRect的重繪機制

一、什么是Quartz2D

Quartz2D是?個二維繪圖引擎,同時支持iOS和Mac系統(tǒng)
Quartz2D的API是純C語?言的Quartz2D的API來自于Core Graphics框架
Quartz2D的數(shù)據(jù)類型和函數(shù)基本都以CG作為前綴,例如下面2個類型:
1.CGContextRef
2.CGPathRef


二喇喉、Quartz 2D能完成的工作
繪制圖形 : 線條\\三角形\\矩形\\圓\\弧,折線圖,餅圖荚恶,柱狀圖
繪制文字
繪制\\生成圖片(圖像)
讀取\\生成PDF
屏幕截圖\\裁剪圖片(例如截取游戲的五殺. 例如將矩形裁剪成圓形)
自定義UI控件
畫板(可以在畫板上畫畫)
手勢解鎖
圖片加水印


三废恋、Quartz2D在iOS開發(fā)中的價值

  • 為了便于搭建美觀的UI界面,iOS提供了UIKit框架绕沈,里面有各種各樣的UI控件肮韧,
    利用UIKit框架提供的控件融蹂,拼拼湊湊,能搭建和現(xiàn)實一些簡單惹苗、常見的UI界面殿较。
UILabel:顯示文字
UIImageView:顯示圖片
UIButton:同時顯示圖片和文字(能點擊)
......
  • 但是,有些UI界面極其復雜桩蓉、而且比較個性化淋纲,用普通的UI控件無法實現(xiàn),這時可以利用Quartz2D技術將控件內部的結構畫出來,類似自定義控件.其實院究,iOS中大部分控件的內容都是通過Quartz2D畫出來的,因此洽瞬,Quartz2D在iOS開發(fā)中很重要的一個價值是:自定義view(自定義UI控件)

四、圖形上下文

圖形上下文(Graphics Context)是一個CGContextRef類型的數(shù)據(jù).

  • 圖形上下文的作用
    • 保存繪圖信息业汰、繪圖狀態(tài)
    • 相當于畫布伙窃,不同類型的畫布就是決定著畫得內容將展示在哪里。
    • 相同的一套繪圖序列样漆,指定不同的Graphics Context为障,就可將相同的圖像繪制到不同的目標上,Quartz2D提供了以下幾種類型的Graphics Context:
    • Bitmap Graphics Context 位圖上下文,在這個上下文上繪制或者渲染的內容放祟,可以獲取成圖片(需要主動創(chuàng)建一個位圖上下文來使用鳍怨,使用完畢,一定要銷毀)
    • PDF Graphics Context
    • Window Graphics Context
    • Layer Graphics Context 圖層上下文跪妥,針對UI控件的上下文
    • Printer Graphics Context


      輸出方式.png

五鞋喇、利用Quartz2D繪制內容到自定義的view上

  • 1.新建一個類,繼承自UIView
  • 2.實現(xiàn)- (void)drawRect:(CGRect)rect方法眉撵,然后在這個方法中,取得跟當前view相關聯(lián)的圖形上下文侦香。
  • 3.繪制相應的圖形內容
  • 4.利用圖形上下文將繪制的所有內容渲染顯示到view上面

六、核心方法drawRect:

  • 為什么要實現(xiàn)drawRect:方法才能繪圖到view上纽疟?
    • 因為在drawRect:方法中才能取得跟view相關聯(lián)的圖形上下文
  • drawRect:方法在什么時候被調用罐韩?
    • 當view第一次顯示到屏幕上時(被加到UIWindow上顯示出來)
    • 調用view的setNeedsDisplay或者setNeedsDisplayInRect:時.
  • 注意4點:
    • 手動調用drawRect:方法,不會自動創(chuàng)建跟View相關聯(lián)的上下文污朽。應該
      調用setNeedsDisplay方法,系統(tǒng)底層會自動調用drawRect伴逸,告訴系統(tǒng)重新繪制View.這樣,系統(tǒng)底層會自動創(chuàng)建跟View相關聯(lián)的上下文
    • setNeedsDisplay底層會調用drawRect,并不是立馬調用的.只是設了一個調用的標志.調用時刻是等下一次屏幕刷新時才去調用drawRect。屏幕每一秒刷新30-60秒次,所以1秒調用drawRect方法大概30-60次,速度非炒砗快哦
    • view內部有個layer(圖層)屬性,drawRect:方法中取得的是一個Layer Graphics Context颓芭,因此顷锰,繪制的東西其實是繪制到view的layer上去了
    • View之所以能顯示東西,完全是因為它內部的layer

七亡问、Quartz2D繪圖的代碼步驟

1.獲得圖形上下文

CGContextRef ctx = UIGraphicsGetCurrentContext();

2.拼接路徑(下面代碼是繪制一條線段)

CGContextMoveToPoint(ctx, 10, 10);
CGContextAddLineToPoint(ctx, 100, 100);

3.繪制路徑

CGContextStrokePath(ctx); // CGContextFillPath(ctx);


八官紫、常用拼接路徑函數(shù)

新建一個起點

void CGContextMoveToPoint(CGContextRef c, CGFloat x, CGFloat y)

添加新的線段到某個點

void CGContextAddLineToPoint(CGContextRef c, CGFloat x, CGFloat y)

添加一個矩形

void CGContextAddRect(CGContextRef c, CGRect rect)

添加一個橢圓

void CGContextAddEllipseInRect(CGContextRef context, CGRect rect)

添加一個圓弧

void CGContextAddArc(CGContextRef c, CGFloat x, CGFloat y,
  CGFloat radius, CGFloat startAngle, CGFloat endAngle, int clockwise)

九、常用繪制路徑函數(shù)

一般以CGContextDraw州藕、CGContextStroke束世、CGContextFill開頭的函數(shù),都是用來繪制路徑的

Mode參數(shù)決定繪制的模式

void CGContextDrawPath(CGContextRef c, CGPathDrawingMode mode)

繪制空心路徑

void CGContextStrokePath(CGContextRef c)

繪制實心路徑

void CGContextFillPath(CGContextRef c)

十床玻、矩陣操作

利用矩陣操作毁涉,能讓繪制到上下文中的所有路徑一起發(fā)生變化

縮放

void CGContextScaleCTM(CGContextRef c, CGFloat sx, CGFloat sy)

旋轉

void CGContextRotateCTM(CGContextRef c, CGFloat angle)

平移

void CGContextTranslateCTM(CGContextRef c, CGFloat tx, CGFloat ty)

十一、案例

  • 特別注意:
M_PI的含義:π
M_PI * 2的含義:2π

M_PI_2的含義:π/2
M_PI / 2的含義:π/2

    // 畫的圖形路徑
    //bezierPathWithArcCenter:弧所在的圓心
    //radius:圓的半徑
    //startAngle:開始角度,圓的最右側為0度
    //endAngle:截至角度,向下為正,向上為負.
    //clockwise:時針的方向,yes:順時針 no:逆時針
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:self.center radius:radius startAngle:startA endAngle:endA clockwise:NO];

    

畫矩形锈死、正方形

- (void)drawRect:(CGRect)rect {
    //1.獲取上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.描述路徑
    UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(50, 50, 200, 200)];
    //3.把路徑添加到上下文
    CGContextAddPath(ctx, path.CGPath);
    
    [[UIColor redColor] set];// 路徑的顏色
    
    //4.把上下文的內容渲染到View的layer.
//    CGContextStrokePath(ctx);// 描邊路徑
    CGContextFillPath(ctx);// 填充路徑

    
}
描邊矩形.png
填充矩形.png

畫扇形

- (void)drawRect:(CGRect)rect {
    
    CGPoint center = CGPointMake(rect.size.width * 0.5, rect.size.height * 0.5);
    CGFloat radius = rect.size.width * 0.5 - 10;
    CGFloat startA = 0;
    CGFloat endA = -M_PI_2;
    // 畫弧的路徑
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:NO];
    // 添加一根線到圓心
    [path addLineToPoint:center];
    // 閉合路徑
    [path closePath];
    // 路徑顏色
    [[UIColor redColor] set];
    // 填充路徑
    [path fill];
    // 描邊路徑
//    [path stroke];
    
    
    
}
描邊扇形.png
填充扇形.png

畫圓形

- (void)drawRect:(CGRect)rect {
    //1.獲取上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.描述路徑
    // cornerRadius:圓角半徑贫堰。矩形的寬高都為200,如果圓角為100待牵,那么兩個角之間弧線上任意一點到矩形中心的距離都為100,所以為圓形
    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(50, 50, 200, 200) cornerRadius:100];
    //3.把路徑添加到上下文
    CGContextAddPath(ctx, path.CGPath);
    
    [[UIColor redColor] set];// 路徑的顏色
    
    //4.把上下文的內容渲染到View的layer.
    // CGContextStrokePath(ctx);// 描邊路徑
    CGContextFillPath(ctx);// 填充路徑
    
}
描邊圓形.png
填充圓形.png

畫圓角矩形

- (void)drawRect:(CGRect)rect {
    //1.獲取上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.描述路徑
    // cornerRadius:圓角半徑其屏。
    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(50, 50, 200, 200) cornerRadius:50];
    //3.把路徑添加到上下文
    CGContextAddPath(ctx, path.CGPath);
    
    [[UIColor redColor] set];// 路徑的顏色
    
    //4.把上下文的內容渲染到View的layer.
   CGContextStrokePath(ctx);// 描邊路徑
//    CGContextFillPath(ctx);// 填充路徑
    
}
描邊圓角矩形.png
填充圓角矩形.png

畫直線

- (void)drawRect:(CGRect)rect {
    
    //1.獲取跟View相關聯(lián)的上下文(uigraphics開頭)
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    
    //2.描述路徑
    //一條路徑可以繪制多條線 路徑:path     路徑繪制多條線:path使用了兩次(2次的起點到終點),都是將線添加到某個點
    UIBezierPath *path = [UIBezierPath bezierPath];
    //設置起點
    [path moveToPoint:CGPointMake(50, 150)];
    //添加一根線Line到某個點
    [path addLineToPoint:CGPointMake(250, 50)];
    
    //畫第二根線
    [path moveToPoint:CGPointMake(50, 250)];
    [path addLineToPoint:CGPointMake(250, 100)];
    
    
    //設置線寬
    CGContextSetLineWidth(ctx, 20);
    //設置線的連接樣式
    CGContextSetLineJoin(ctx, kCGLineJoinBevel);
    //設置線的頂角樣式
    CGContextSetLineCap(ctx, kCGLineCapRound);// 圓角線條
    //設置線條顏色
    [[UIColor redColor] set];
    
    //3.把路徑添加到上下文
    CGContextAddPath(ctx, path.CGPath);
    //4.把上下文當中繪制的內容渲染到跟View關聯(lián)的layer
    CGContextStrokePath(ctx);

    
}
線條.png
相交線條.png

畫不規(guī)則圖形+添加點擊事件

CustomView.h文件

#import <UIKit/UIKit.h>

@interface CustomView : UIView
@property (nonatomic ,strong) UIBezierPath *bezierPath;
@property (nonatomic, strong) UIColor *fillColor;

@end

CustomView.m文件

#import "CustomView.h"

@implementation CustomView

-(void)drawRect:(CGRect)rect{
    _bezierPath = [UIBezierPath bezierPath];
    [_bezierPath moveToPoint:CGPointMake(320, 70)];
    [_bezierPath addLineToPoint: CGPointMake(30, 130)];
    [_bezierPath addLineToPoint: CGPointMake(80, 400)];
    [_bezierPath addLineToPoint: CGPointMake(370, 570)];
    [_bezierPath closePath];
    
    //設置填充色(fillColor屬性存儲著外界賦給它的黃色)
    [_fillColor setFill];
    // 填充路徑
    [_bezierPath fill];
    
    //設置描邊色
    [UIColor.redColor setStroke];
     _bezierPath.lineWidth = 4;
    // 描邊路徑
    [_bezierPath stroke];
}
@end

ViewController.m文件

#import "ViewController.h"
#import "CustomView.h"
@interface ViewController ()
@property (nonatomic, strong) CustomView *customView;
@end

@implementation ViewController

- (void)viewDidLoad {
    
    //創(chuàng)建充滿整個屏幕的自定義View 并在自定義View中繪制圖形
    _customView = [[CustomView alloc] initWithFrame:self.view.bounds];
    _customView.backgroundColor = [UIColor greenColor];
    [self.view addSubview:_customView];
    
    //給自定義View添加點擊事件
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(TapGestureRecognizer:)];
    [_customView addGestureRecognizer:tap];
    
}

- (void)TapGestureRecognizer:(UITapGestureRecognizer *)gesture{
       // 獲得手指在當前View上的點(位置)
    CGPoint tapPoint = [gesture locationInView:_customView];
    
    //判斷點是否在繪制的路徑內部
    if ([_customView.bezierPath containsPoint:tapPoint]){
        _customView.fillColor = [UIColor yellowColor];
        // 重繪
        [_customView setNeedsDisplay];
    }
}

@end
不規(guī)則圖形+點擊事件.gif

畫曲線

  • 本塞爾曲線原理


    貝塞爾曲線.gif
- (void)drawRect:(CGRect)rect {
    //1.獲取跟View相關聯(lián)的上下文.
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.描述路徑
    UIBezierPath *path = [UIBezierPath  bezierPath];
    //畫曲線,設置起點.還有一個控制點(用來控制曲線的方向跟彎曲程度)
    //設置起點.
    [path moveToPoint:CGPointMake(10, 150)];
    //添加一要曲線到某個點
    [path addQuadCurveToPoint:CGPointMake(200, 150) controlPoint:CGPointMake(150, 10)];
    //3.把路徑添加到上下文當中.
    CGContextAddPath(ctx, path.CGPath);
    //4.把上下文的內容渲染View上.
    CGContextStrokePath(ctx);
    
}
曲線.png

畫餅圖

  • 做法1:
- (void)drawRect:(CGRect)rect {
     NSArray *dataArray =  @[@25,@25,@50];
    // 畫弧
    CGPoint center = CGPointMake(rect.size.width * 0.5, rect.size.height * 0.5);
    // 半徑
    CGFloat radius = rect.size.width * 0.5 - 10;
    
    CGFloat startA = 0;
    CGFloat angle = 0;
    CGFloat endA = 0;
    
    for (NSNumber *num in dataArray) {
        startA = endA;
        // 遍歷出第一個對象25,angle =25/100 *2π缨该,即angle = π/2偎行,所以為1/4圓,
        angle = num.intValue / 100.0 * M_PI * 2;
        // 截至角度= 開始的角度+ 遍歷出的對象所占整個圓形的角度
        endA = startA + angle;
        // 順勢針畫貝塞爾曲線
        UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:YES];
        // 設置隨機顏色
        [[self randomColor] set];
        // 添加一根線到圓心
        [path addLineToPoint:center];
        // 填充路徑
   //    [path fill];
        // 描邊路徑
        [path stroke];
    }
    
}
描邊餅圖.png
填充餅圖.png
- (void)drawRect:(CGRect)rect {
     NSArray *dataArray =  @[@25,@25,@50];
    // 畫弧
    CGPoint center = CGPointMake(rect.size.width * 0.5, rect.size.height * 0.5);
    // 半徑
    CGFloat radius = rect.size.width * 0.5 - 10;
    CGFloat startA = 0;
    CGFloat angle = 0;
    CGFloat endA = 0;
    
    for (NSNumber *num in dataArray) {
        
        startA = endA;
        // 遍歷出第一個對象25,angle =25/100 *2π,即angle = π/2贰拿,所以為1/4圓,
        angle = num.intValue / 100.0 * M_PI * 2;
        // 截至角度= 開始的角度+ 遍歷出的對象所占整個圓形的角度
        endA = startA + angle;
        // 順勢針畫貝塞爾曲線
        UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:YES];
        // 設置隨機顏色
        [[self randomColor] set];
        // 添加一根線到圓心
        [path addLineToPoint:center];
        // 填充路徑
       [path fill];
        // 描邊路徑
//        [path stroke];
    }
}

//隨機生成一個顏色
- (UIColor *)randomColor {
    
    CGFloat r = arc4random_uniform(256) / 255.0;
    CGFloat g = arc4random_uniform(256) / 255.0;
    CGFloat b = arc4random_uniform(256) / 255.0;
    
    return  [UIColor colorWithRed:r green:g blue:b alpha:1];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
    //重繪
    [self setNeedsDisplay];
    
}
重繪.gif
  • 做法2:
- (void)drawRect:(CGRect)rect {
    
    CGPoint center = CGPointMake(self.bounds.size.width * 0.5, self.bounds.size.height * .5);
    CGFloat radius = self.bounds.size.width * 0.5 - 10;
    CGFloat startA = 0;
    CGFloat endA = 25 / 100.0 * M_PI * 2;
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:YES];
    [[UIColor redColor] set];
    //添加一根線到圓心
    [path addLineToPoint:center];
    [path fill];
    
    //第二個扇形
    startA = endA;
    CGFloat angle = 25 / 100.0 * M_PI * 2;
    endA = startA + angle;
    UIBezierPath *path2 = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:YES];
    [[UIColor greenColor] set];
    //添加一根線到圓心
    [path2 addLineToPoint:center];
    [path2 fill];
    
    startA = endA;
    angle = 50 / 100.0 * M_PI * 2;
    endA = startA + angle;
    UIBezierPath *path3 = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:YES];
    [[UIColor blueColor] set];
    //添加一根線到圓心
    [path3 addLineToPoint:center];
    [path3 fill];}

//隨機生成一個顏色
- (UIColor *)randomColor {
    
    CGFloat r = arc4random_uniform(256) / 255.0;
    CGFloat g = arc4random_uniform(256) / 255.0;
    CGFloat b = arc4random_uniform(256) / 255.0;
    
    return  [UIColor colorWithRed:r green:g blue:b alpha:1];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
    //重繪
    [self setNeedsDisplay];
    
}
餅圖-做法2.png

畫文字

- (void)drawRect:(CGRect)rect {
    NSString *str = @"簡書:CoderZb";
    
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    //設置字體
    dict[NSFontAttributeName] = [UIFont systemFontOfSize:30];
    //設置顏色
    dict[NSForegroundColorAttributeName] = [UIColor redColor];
    //設置描邊
    dict[NSStrokeColorAttributeName] = [UIColor blueColor];
    dict[NSStrokeWidthAttributeName] = @3;
    //設置陰影
    NSShadow *shadow = [[NSShadow alloc] init];
    shadow.shadowColor = [UIColor greenColor];
    shadow.shadowOffset = CGSizeMake(-2, -2);
    shadow.shadowBlurRadius = 3;
    dict[NSShadowAttributeName] = shadow;
    
    //設置文字的屬性
    //drawAtPoint不會自動換行
    //[str drawAtPoint:CGPointMake(0, 0) withAttributes:dict];
    //drawInRect會自動換行
    [str drawInRect:self.bounds withAttributes:dict];

}

文字.png

模擬系統(tǒng)UIImageView是如何畫出圖片的
底層調用了 [self setNeedsDisplay];進行重繪,接著調用drawRect:畫出圖片

  • ViewController.m文件
#import "ViewController.h"
#import "ZBImageView.h"

@interface ViewController ()
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    ZBImageView *ImageV = [[ZBImageView alloc] init];
    ImageV.frame = CGRectMake(0, 0,self.view.frame.size.width, 400);
    ImageV.image = [UIImage imageNamed:@"AA"];
    [self.view addSubview:ImageV];
}
@end
  • ZBImageView.h文件
#import <UIKit/UIKit.h>

@interface ZBImageView : UIView

@property (nonatomic ,strong) UIImage *image;

@end
  • ZBImageView.m文件

#import "ZBImageView.h"

@implementation ZBImageView

- (void)setImage:(UIImage *)image {
    _image = image;
    //重繪
    [self setNeedsDisplay];
}

- (void)drawRect:(CGRect)rect {
    
    [self.image drawInRect:rect];
    NSLog(@"%s",__func__);
}

@end


#import "VCView.h"

@implementation VCView

- (void)awakeFromNib {
    
    //添加定時器
    //[NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(update) userInfo:nil repeats:YES];
    
    //多久調用update方法?當下一次屏幕刷新時調用(屏幕每一秒刷新30-60秒次,所以1秒調用update方法大概30-60次)
    CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(update)];
    
    //想要讓CADisplayLink工作, 必須得要添加到運行循環(huán)當中.
   [link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
    
    
    //setNeedsDisplay底層會調用drawRect,并不是立馬調用的.只是設了一個調用的標志.調用時刻是等下一次屏幕刷新時才去調用drawRect
}

static int _snowY = 0;
- (void)update {
    
    NSLog(@"%s",__func__);
    _snowY += 10;
    if (_snowY > self.bounds.size.height) {
        _snowY = 0;
    }
    //重繪
    [self setNeedsDisplay];
    
}

- (void)drawRect:(CGRect)rect {
    
    //加載圖片
    UIImage *image = [UIImage imageNamed:@"雪花"];
    [image drawAtPoint:CGPointMake(0, _snowY)];
    
}

@end



畫圖片.png

矩陣之縮放蛤袒、移動、旋轉UIView

- (void)drawRect:(CGRect)rect {
    // Drawing code
    
    //1.獲取上下文
    CGContextRef ctx =  UIGraphicsGetCurrentContext();
    
    UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(200, 100, 200, 100)];
    [[UIColor redColor] set];
    
    //縮放
     CGContextScaleCTM(ctx, 0.5, 0.5);
    //移動
     CGContextTranslateCTM(ctx, 150,200);
    
    //旋轉
     CGContextRotateCTM(ctx, M_PI_4);
    
    
    CGContextAddPath(ctx, path.CGPath);
    CGContextFillPath(ctx);
    
}
原始.png
縮放.png
移動.png
旋轉.png

雪花+CA定時器+drawRect

- (void)awakeFromNib {
    //方式1:NSTimer定時器
    //[NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(update) userInfo:nil repeats:YES];
    
    //方式2:CADisplayLink.  多久調用update方法?當下一次屏幕刷新時調用(屏幕每一秒刷新30-60秒次,所以1秒調用update方法大概30-60次)
    CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(update)];
    
    //想要讓CADisplayLink工作, 必須得要添加到運行循環(huán)當中.
    [link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
    
    
    //setNeedsDisplay底層會調用drawRect,并不是立馬調用的.只是設了一個調用的標志.調用時刻是等下一次屏幕刷新時才去調用drawRect
}

static int _snowY = 0;
- (void)update {
    
    NSLog(@"%s",__func__);
    _snowY += 10;
    if (_snowY > self.bounds.size.height) {
        _snowY = 0;
    }
    //重繪
    [self setNeedsDisplay];
    
}
- (void)drawRect:(CGRect)rect {
    
    //加載圖片
    UIImage *image = [UIImage imageNamed:@"雪花"];
    [image drawAtPoint:CGPointMake(0, _snowY)];
    
}
雪花.gif

畫水印

#import "ViewController.h"

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imageV;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
   
    //生成一張圖片
    //0.加載圖片
    UIImage *oriImage = [UIImage imageNamed:@"壁紙"];
    //1.創(chuàng)建位圖上下文(size:開啟多大的上下文,就會生成多大的圖片)
    UIGraphicsBeginImageContext(oriImage.size);
    //2.把圖片繪制到上下文當中
    [oriImage drawAtPoint:CGPointZero];
    //3.繪制水印(雖說UILabel可以快速實現(xiàn)這種效果壮不,但是我們也可以繪制出來)
    NSString *str = @"簡書:CoderZb";
    
    
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    dict[NSFontAttributeName] = [UIFont systemFontOfSize:20];
    dict[NSForegroundColorAttributeName] = [UIColor redColor];
    
    [str drawAtPoint:CGPointZero withAttributes:dict];
    //4.從上下文當中生成一張圖片
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    //5.關閉位圖上下文
    UIGraphicsEndImageContext();
    
    
    self.imageV.image = newImage;
}
@end
水印.png

裁剪圖片

#import "ViewController.h"

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imageV;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //1.確定邊框的寬度
    CGFloat borderW = 10;
    //2.加載圖片
    UIImage *oriImage = [UIImage imageNamed:@"頭像"];
    //3.開啟位圖上下文(大小 原始圖片的寬高度+ 2 *邊框寬度)
    CGSize size = CGSizeMake(oriImage.size.width + 2 * borderW, oriImage.size.height + 2 * borderW);
    UIGraphicsBeginImageContext(size);
    //4.繪制邊框(大圓)
    UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, size.width, size.height)];
    [[UIColor yellowColor] set];
    [path fill];
    //5.繪制小圓(把小圓設置成裁剪區(qū)域)
    UIBezierPath *clipPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(borderW, borderW, oriImage.size.width, oriImage.size.height)];
    [clipPath addClip];
    //6.把圖片繪制到上下文當中
    [oriImage drawAtPoint:CGPointMake(borderW, borderW)];
    //7.從上下文當中生成圖片
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    //8.關閉上下文.
    UIGraphicsEndImageContext();
    //9.顯示新圖片
    self.imageV.image = newImage;
}
裁剪圖片.png

屏幕截圖

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
    //生成圖片
    //1.開啟一個位圖上下文
    UIGraphicsBeginImageContext(self.view.bounds.size);
    //2.把View的內容繪制到上下文當中
    CGContextRef ctx =  UIGraphicsGetCurrentContext();
    //UIView內容想要繪制到上下文當中, 必須使用渲染的方式
    [self.view.layer renderInContext:ctx];
    //3.從上下文當中生成一張圖片
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    //4.關閉上下文
    UIGraphicsEndImageContext();
    //把圖片轉成二進制流
    //NSData *data = UIImageJPEGRepresentation(newImage, 1);
    NSData *data = UIImagePNGRepresentation(newImage);
    
    [data writeToFile:@"/Users/zhangbin/Desktop/CoderZbCoderZbCoderZb.jpg" atomically:YES];
    
}

@end
101.125.gif

配合手勢裁剪圖片


#import "ViewController.h"

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imageV;
@property (nonatomic, assign)CGPoint startP;

@property (nonatomic, weak) UIView *coverView;

@end

@implementation ViewController

-(UIView *)coverView {

    if (_coverView == nil) {
        //創(chuàng)建UIView
        UIView *coverView = [[UIView alloc] init];
        coverView.backgroundColor = [UIColor blackColor];
        coverView.alpha = 0.7;
        _coverView = coverView;
        [self.view addSubview:coverView];
    }
    return _coverView;
    
}

- (IBAction)pan:(UIPanGestureRecognizer *)pan {
    
    //獲取當前手指所在的點
    CGPoint curP = [pan locationInView:self.imageV];
    // 判斷手勢的狀態(tài)
    // 要執(zhí)行2,那么1必須執(zhí)行過汗盘。聯(lián)想一下點擊圖片的過程就理解了。
   // 要執(zhí)行3,那么1,2也必須執(zhí)行過询一。
    if(pan.state == UIGestureRecognizerStateBegan) {// 1
        //記錄當前手指的開始點
        self.startP = curP;
        
    } else if(pan.state == UIGestureRecognizerStateChanged) {// 2
        
        //rect
        CGFloat w = curP.x - self.startP.x;
        CGFloat h = curP.y - self.startP.y;
        CGRect rect = CGRectMake(self.startP.x, self.startP.y, w, h);
        
        self.coverView.frame = rect;
      
        
    }else if(pan.state == UIGestureRecognizerStateEnded) {// 3
        
        
        //生成一張圖片
        UIGraphicsBeginImageContext(self.imageV.bounds.size);
        
        //設置裁剪區(qū)域
        UIBezierPath *path = [UIBezierPath bezierPathWithRect:self.coverView.frame];
        [path addClip];
        
        //2.把UIImageV當中的內容渲染到上下文當中
        CGContextRef ctx = UIGraphicsGetCurrentContext();
        [self.imageV.layer renderInContext:ctx];
        
        //從上下文當中獲取圖片
        UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
        
        //關閉上下文
        UIGraphicsEndImageContext();
        
        self.imageV.image = newImage;
        
        [self.coverView removeFromSuperview];
    }
}
@end
101.126.gif

配合手勢擦除圖片

#import "ViewController.h"

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imageV;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.imageV.userInteractionEnabled = YES;
    
    //添加手勢
    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
    [self.imageV addGestureRecognizer:pan];
    
    
}

- (void)pan:(UIPanGestureRecognizer *)pan {
    
    CGFloat rectWH = 20;
    //獲取當前手指的點
    CGPoint curP = [pan locationInView:self.imageV];
     // 當手指在(curP.x,curP.y)的位置上時隐孽,就讓這個位置的x和y之分別減去10像素耐薯,由此CGRectMake(x, y, rectWH, rectWH)構成的形狀就是正方形泽本,以后把這個正方形作為擦除的區(qū)域
    CGFloat x = curP.x - rectWH * 0.5;
    CGFloat y = curP.y - rectWH * 0.5;
    CGRect rect = CGRectMake(x, y, rectWH, rectWH);
    
    
    //開啟一個位圖上下文
    //UIGraphicsBeginImageContext(self.imageV.bounds.size);
    UIGraphicsBeginImageContextWithOptions(self.imageV.bounds.size, NO, 0);
    
    
    
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //把UIImageV的內容渲染到上下文當中
    [self.imageV.layer renderInContext:ctx];
    
    //擦除上下文當中指定的區(qū)域(即正方形區(qū)域(x, y, rectWH, rectWH) )
    CGContextClearRect(ctx, rect);
    
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    self.imageV.image = newImage;
    
    //關閉上下文
    UIGraphicsEndImageContext();
    
    
    
}

@end
101.127.gif

配合UITouch實現(xiàn)手勢解鎖鏈接密碼

  • 部分代碼:
#import "ClockView.h"
#import "SVProgressHUD/SVProgressHUD.h"

#define kDefaultBackNumber @"01258"
@interface ClockView()

@property (nonatomic ,strong) NSMutableArray *selectBtnArray;

@property (nonatomic, assign) CGPoint  curP;

@end

@implementation ClockView

- (NSMutableArray *)selectBtnArray {
    
    if (_selectBtnArray == nil) {
        _selectBtnArray = [NSMutableArray array];
    }
    return _selectBtnArray;
}

- (void)awakeFromNib {
    //添加子控件
    [self setUp];
}

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        //添加子控件
        [self setUp];
    }
    return self;
}

//添加子控件
- (void)setUp {
    
    for (int i = 0; i < 9; i++) {
        
        //創(chuàng)建按鈕
        UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
        btn.userInteractionEnabled = NO;
        
        //如果寫成btn.userInteractionEnabled=YES或者不寫,那么點擊按鈕的響應事件由按鈕的高亮狀態(tài)響應(處理)了资铡,就不會傳遞給父控件(上一個響應者)處理了,也就不會執(zhí)行父控件所在的類中的touchesBegan方法了.
        
        //如果寫成btn.userInteractionEnabled=NO雹顺,即不讓按鈕與用戶交互文兑,響應事件傳遞給父控件(ClockView)韭山,又因為在ClockView類里面寫了touchesBegan方法虚倒,所以會執(zhí)行touchesBegan方法
        btn.tag = i;
        //設置按鈕的圖片
        [btn setImage:[UIImage imageNamed:@"空心圓圈"] forState:UIControlStateNormal];
        
        //設置選中狀態(tài)下的圖片
        [btn setImage:[UIImage imageNamed:@"gesture_node_selected"] forState:UIControlStateSelected];
        
        [self addSubview:btn];
    }
}

//按功能模塊抽方法
//獲取當前手指的點
- (CGPoint)getCurPoint:(NSSet *)touches {//CGPoint后面沒有*烙荷,強烈注意
    //1獲取當前手指的點
    
    //1.1當用戶用一根手指觸摸屏幕時嫡锌,會創(chuàng)建一個與手指相關聯(lián)的UITouch對象
    UITouch *touch = [touches anyObject];
    //1.2手指在當前view上的位置
    CGPoint curP =  [touch locationInView:self];
    return curP;
}

//給定一個點,判斷這個點在不在按鈕身上
//如果沒有找到符合的條件,直接返回nil.
- (UIButton *)btnContainsPoint:(CGPoint)point {
    //取出所有的子控件.
    for (UIButton *btn in self.subviews) {
        // 判斷當前點在不在按鈕身上.
        if (CGRectContainsPoint(btn.frame, point)) {
            
            //如果在的話, 讓按鈕成為選中狀態(tài)
            
            return btn;
        }
    }
    return nil;
}

//手指開始點擊
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    //獲取當前手指的點
    CGPoint curP = [self getCurPoint:touches];
    //給定一個點,判斷這個點在不在按鈕身上
    UIButton *btn = [self btnContainsPoint:curP];
    if(btn && btn.selected == NO) {
        btn.selected = YES;
        //保存選中的按鈕
        [self.selectBtnArray addObject:btn];
    }
    
}

//手指移動
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
    //獲取當前手指的點
    CGPoint curP = [self getCurPoint:touches];
    
    //在手指移動的過程中虑稼,邊移動手指琳钉,邊用self.curP保存當前手指的點
    self.curP = curP;
    
    //取出所有的子控件.
    //給定一個點,判斷這個點在不在按鈕身上
    UIButton *btn = [self btnContainsPoint:curP];
    if(btn && btn.selected == NO) {
        btn.selected = YES;
        //保存選中的按鈕
        [self.selectBtnArray addObject:btn];
    }
    
    //重繪
    [self setNeedsDisplay];
}

 //手指離開
 - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
 {
 //所有選中按鈕取消選中狀態(tài)
 
 NSMutableString *str = [NSMutableString string];
     
     for (UIButton *btn in self.selectBtnArray) {
     btn.selected = NO;
     [str appendFormat:@"%ld",btn.tag];
    
     }
     
     NSLog(@"%@",str);

 // 無論是畫路徑還是清空路徑,必須得調用setNeedsDisplay
     
 //清空路徑
 [self.selectBtnArray removeAllObjects];
 
 //清空路徑還必須調用重繪方法
 [self setNeedsDisplay];
     
     if([str isEqualToString:kDefaultBackNumber]){
         NSLog(@"跳轉");
         // 發(fā)出通知
         [[NSNotificationCenter defaultCenter] postNotificationName:@"CoderZb" object:nil userInfo:nil];
     }else{
         [SVProgressHUD showErrorWithStatus:@"手勢錯誤"];
     }
     
 }

- (void)drawRect:(CGRect)rect {
    
    if (self.selectBtnArray.count) {//view開始顯示之前會調用drawRect方法,此時方法里面沒有任何值蛛倦,數(shù)組里面也沒有值歌懒,所以要先判斷,if (self.selectBtnArray.count)溯壶,如果沒有值及皂,就不執(zhí)行if里面的內容
        
        //描述路徑
        UIBezierPath *path = [UIBezierPath bezierPath];
        //取出所有選中的按鈕
        
        for (int i = 0; i < self.selectBtnArray.count; i++) {
            //取出每一個按鈕
            UIButton *btn =  self.selectBtnArray[i];
            
            if (i == 0) {// selectBtnArray數(shù)組中的第0個對象
                //讓selectBtnArray數(shù)組中的第0個對象按鈕成為路徑的起點。第0個對象是9個按鈕中的任意一個,因為點擊哪個按鈕由用戶自己決定的且改。
                [path moveToPoint:btn.center];
            }else {// 不是selectBtnArray數(shù)組中的第0個元素
                // 如果不是起點验烧,說明起點在之前已經確定了,我們只需要劃線到第1個對象按鈕又跛。同樣碍拆,這第一個對象按鈕也是9個按鈕中的任意一個
                [path addLineToPoint:btn.center];//1
            }
            //區(qū)分1和2:1在手指拖動的過程中不顯示線,拖動到按鈕身上效扫,線才顯示倔监。2在手指在拖動的過程中,邊拖動邊顯示 線菌仁。巧:2是對1的補充
        }
        
        //添加一根線到當前手指所在的點
        //[path addLineToPoint:self.curP];//2     touchesMoved方法中保存(self.curP = curP;)了手指在移動過程中的所有點浩习,并利用 [self setNeedsDisplay]方法,實際是底層調用了drawRect:方法济丘。所以在2中可以拿到手指在移動過程中的所有點谱秽,最后一個點肯定是當前的點,倒數(shù)第二個點相對于倒數(shù)第三個點來說摹迷,就是當前的點疟赊,以此類推,利用[path addLineToPoint:self.curP];將線添加到當前手指所在的點(手指在拖動的過程中峡碉,實際是有很多點近哟,再加上后面的點相對于前面的點來說始終是當前的點,所以最終造成了邊拖動邊有線的結果)
        
        //設置線的狀態(tài)
        [path setLineWidth:10];
        // 紅色路徑
        [[UIColor redColor] set];
        [path setLineJoinStyle:kCGLineJoinRound];
        // 描邊路徑
        [path stroke];
        
    }
    
}

- (void)layoutSubviews {
    [super layoutSubviews];
    
    CGFloat x = 0;
    CGFloat y = 0;
    CGFloat btnWH = 74;
    
    int column = 3;
    CGFloat margin = (self.bounds.size.width - column * btnWH) / (column + 1);
    
    int curColumn = 0;
    int curRow = 0;
    
    //取出每一個子控件,設置frame.    self.subviews.count值為9
    for (int i = 0 ; i < self.subviews.count; i++) {
        // 九宮格布局鲫寄。獲取到的列和行本質是坐標(0,0)(0,1)(0,2)(1,0)(1,1)(1,2)(2,0)(2,1)(2,1)
        
        //當前所在的列
        curColumn = i % column;
        //當前所在的行
        curRow = i / column;
        
        x = margin + (margin + btnWH) * curColumn;
        y = margin + (margin + btnWH) * curRow;
        
        //取出每一按鈕
        UIButton *btn = self.subviews[i];
        // 確定每個按鈕的frame
        btn.frame = CGRectMake(x, y, btnWH, btnWH);
    }
    
}
@end
  • 關鍵函數(shù)

CGRectContainsPoint(btn.frame, point)// 判斷點point是否在btn中

101.138.gif

畫板

iOS9 出現(xiàn)的Stack View控件,實現(xiàn)放置在Stack View內部的子控件的自動布局吉执,相比于手動對每個控件設置約束,Stack View更加效率和精準地来。我們只需要在Stack View選項卡中設置對應的屬性(Distribution,Spacing)即可戳玫。

兩個屬性.png

ViewController.m文件

#import "ViewController.h"
#import "DrawView.h"

@interface ViewController ()<UINavigationControllerDelegate,UIImagePickerControllerDelegate>

@property (weak, nonatomic) IBOutlet DrawView *drawView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
}
//屬于誰的事, 誰來做
//清屏

- (IBAction)clear:(id)sender {
     [self.drawView clear];
}
//撤銷
- (IBAction)undo:(id)sender {
    [self.drawView undo];
}

//橡皮擦
- (IBAction)erase:(id)sender {
    [self.drawView erase];
}
//選擇照片
- (IBAction)photo:(id)sender {
    
    UIImagePickerController *pickVC = [[UIImagePickerController alloc] init];
    //設置照片來源
    pickVC.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
    
    //設置代理
    pickVC.delegate = self;
    
    [self presentViewController:pickVC animated:YES completion:nil];
    
}

//#pa - mark UIImagePickerControllerDelegate
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info {
    
    NSLog(@"%@",info);
    UIImage *image =  info[UIImagePickerControllerOriginalImage];
    //    NSData *data = UIImagePNGRepresentation(image);
    //    [data writeToFile:@"/Users/xiaomage/Desktop/image.png" atomically:YES];
    //
    self.drawView.image = image;
    
    [self dismissViewControllerAnimated:YES completion:nil];
}

//保存
- (IBAction)save:(id)sender {
    
    //對畫板作截屏
    //1.開啟一個位圖上下文
    UIGraphicsBeginImageContext(self.drawView.bounds.size);
    //2.把畫板的內容渲染到上下文當中.
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    [self.drawView.layer renderInContext:ctx];
    //3.從上下文當中取出一張圖片
    UIImage *newImage =  UIGraphicsGetImageFromCurrentImageContext();
    //4.關閉上下文
    UIGraphicsEndImageContext();
    //5.把生成的圖片寫入到系統(tǒng)相冊當中
    //注意:寫放完成時調用的方法必須得是didFinishSavingWithError;
    UIImageWriteToSavedPhotosAlbum(newImage, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
    
    
}

//當寫入完成時調用
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
    NSLog(@"%s",__func__);
}

- (void)success {
    
}
//設置線寬度
- (IBAction)setLineWith:(UISlider *)sender {
    
    [self.drawView setLineWidth:sender.value];
    
}
//設置線的顏色
- (IBAction)setLineColor:(UIButton *)sender {
    [self.drawView setLineColor:sender.backgroundColor];
}

- (BOOL)prefersStatusBarHidden {
    return YES;
}

@end
  • DrawView.h文件
#import <UIKit/UIKit.h>

@interface DrawView : UIView

//清屏
- (void)clear;
//撤銷
- (void)undo;
//橡皮擦
- (void)erase;
//設置線寬度
- (void)setLineWidth:(CGFloat)width;
//設置線的顏色
- (void)setLineColor:(UIColor *)color;

@property (nonatomic ,strong) UIImage *image;

@end
  • DrawView.m文件
#import "DrawView.h"
#import "MyBezierPath.h"

@interface DrawView()

/** <#注釋#>*/
@property (nonatomic ,strong) UIBezierPath *path;

/** <#注釋#>*/
@property (nonatomic ,strong) NSMutableArray *pathArray;

@property (nonatomic , assign) CGFloat width;

/** <#注釋#>*/
@property (nonatomic ,strong) UIColor *color;

@end

@implementation DrawView

- (void)setImage:(UIImage *)image {
    _image = image;
    [self.pathArray addObject:image];
    //重繪
    [self setNeedsDisplay];
}

//清屏
- (void)clear {
    //清空所有的路徑
    [self.pathArray removeAllObjects];
    //重繪
    [self setNeedsDisplay];
}
//撤銷
- (void)undo {
    //刪除最后一個路徑
    [self.pathArray removeLastObject];
    //重繪
    [self setNeedsDisplay];
}
//橡皮擦
- (void)erase {
    
    [self setLineColor:[UIColor whiteColor]];
}

//設置線寬度
- (void)setLineWidth:(CGFloat)width {
    
    self.width = width;
}
////設置線的顏色
- (void)setLineColor:(UIColor *)color {
    self.color = color;
}

- (NSMutableArray *)pathArray {
    
    if (_pathArray == nil) {
        _pathArray = [NSMutableArray array];
    }
    return _pathArray;
}

- (void)awakeFromNib {
    
    //添加手勢
    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
    [self addGestureRecognizer:pan];
    
    self.width = 1;
    // 將黑色存儲到color屬性中
    self.color = [UIColor blackColor];
}

- (void)pan:(UIPanGestureRecognizer *)pan {
    
    //畫線
    //獲取當前手指的點
    CGPoint curP = [pan locationInView:self];
    if (pan.state == UIGestureRecognizerStateBegan) {
        //創(chuàng)建路徑
        //如果發(fā)現(xiàn)系統(tǒng)的類型沒有辦法瞞足要求時,自定義類.繼承原來的類,在原來類的基礎上,添加屬于自己的東西.
        MyBezierPath *path = [[MyBezierPath alloc] init];
        [path setLineWidth:self.width];
        [path setLineJoinStyle:kCGLineJoinRound];
        [path setLineCapStyle:kCGLineCapRound];
        // 取出等號右邊color存儲的顏色賦值給左邊的color(外界如果設置了顏色,那么會覆蓋掉黑色)
        path.color = self.color;
        // 將path作為全局變量,供別的方法訪問
        self.path = path;
        //path這個對象是個空的未斑,應該放到第二個if里面吧咕宿。
        [self.pathArray addObject:path];
        [path moveToPoint:curP];
    } else if (pan.state == UIGestureRecognizerStateChanged) {
        //畫的應該為直線,為什么是任意的線(也能畫曲線)?你這句話是錯誤的府阀。因為你給DrawView添加了手勢缆镣,所以畫的每一個點都會被記錄到,兩點之間確實是直線,但是如果任意兩個相鄰的點的距離都是1像素的話肌似,每條線稍微彎折一點點,那么1000個點肯定能形成平滑的曲線
        [self.path addLineToPoint:curP];
        //將手勢+貝塞爾曲線得到的每一個點繪制成路徑(本質調用drawRect:)
        [self setNeedsDisplay];
    }
    
}
// 繪制路徑
- (void)drawRect:(CGRect)rect {
    
    //繪制出保存的所有路徑
    for (MyBezierPath *path in self.pathArray) {
        
        if ([path isKindOfClass:[UIImage class]]) {
            UIImage *image = (UIImage *)path;
            // 在圖片中繪制路徑
            [image drawInRect:rect];
        }else {
            [path.color set];
            [path stroke];
        }
        
    }
    
}

@end
  • MyBezierPath.h文件
#import <UIKit/UIKit.h>

@interface MyBezierPath : UIBezierPath
@property (nonatomic ,strong) UIColor *color;

@end

[LS](https://pan.baidu.com/s/1gfqLmeB 密碼 492d)
效果:

101.139.gif

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末费就,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子川队,更是在濱河造成了極大的恐慌,老刑警劉巖睬澡,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件固额,死亡現(xiàn)場離奇詭異,居然都是意外死亡煞聪,警方通過查閱死者的電腦和手機斗躏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來昔脯,“玉大人啄糙,你說我怎么就攤上這事≡浦桑” “怎么了隧饼?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長静陈。 經常有香客問我燕雁,道長,這世上最難降的妖魔是什么鲸拥? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任拐格,我火速辦了婚禮,結果婚禮上刑赶,老公的妹妹穿的比我還像新娘捏浊。我一直安慰自己,他們只是感情好撞叨,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布金踪。 她就那樣靜靜地躺著,像睡著了一般谒所。 火紅的嫁衣襯著肌膚如雪热康。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天劣领,我揣著相機與錄音姐军,去河邊找鬼。 笑死,一個胖子當著我的面吹牛奕锌,可吹牛的內容都是我干的著觉。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼惊暴,長吁一口氣:“原來是場噩夢啊……” “哼饼丘!你這毒婦竟也來了?” 一聲冷哼從身側響起辽话,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤肄鸽,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后油啤,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體典徘,經...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年益咬,在試婚紗的時候發(fā)現(xiàn)自己被綠了逮诲。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡幽告,死狀恐怖梅鹦,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情冗锁,我是刑警寧澤齐唆,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站蒿讥,受9級特大地震影響蝶念,放射性物質發(fā)生泄漏。R本人自食惡果不足惜芋绸,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一媒殉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧摔敛,春花似錦廷蓉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至行楞,卻和暖如春攒暇,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背子房。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工形用, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留就轧,地道東北人。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓田度,卻偏偏與公主長得像妒御,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子镇饺,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內容

  • --繪圖與濾鏡全面解析 概述 在iOS中可以很容易的開發(fā)出絢麗的界面效果乎莉,一方面得益于成功系統(tǒng)的設計,另一方面得益...
    韓七夏閱讀 2,727評論 2 10
  • Quartz2D以及drawRect的重繪機制字數(shù)1487 閱讀21 評論1 喜歡1一奸笤、什么是Quartz2D Q...
    PurpleWind閱讀 773評論 0 3
  • Quartz2D 簡介 Quartz2D是二維(平面)的繪圖引擎(經包裝的函數(shù)庫惋啃,方便開發(fā)者使用。也就是說蘋果幫我...
    iOS_Cqlee閱讀 632評論 0 2
  • 什么是Quartz2D 是一個二維的繪圖引擎,同時支持iOS和Mac系統(tǒng) Quartz2D的API是純C語言的,它...
    Mario_ZJ閱讀 587評論 0 1
  • Quartz2D 介紹监右?Quartz2D是一個二維繪圖引擎肥橙,同時支持iOS和Mac系統(tǒng)(跨平臺)。有些UI界面極其...
    冷漠叻葒顏閱讀 909評論 1 7