iOS开发之Quartz 2D绘图

本文介绍Quartz2D图形引擎及其在iOS和macOS开发中的应用。通过详细解析Quartz2D的基本概念与绘图流程,文章提供了一个自定义绘图功能的示例,包括触摸事件处理、路径绘制、颜色与线宽的选择等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Quartz 2D是一个二维图形绘制引擎,支持iOS环境和Mac OS X环境

Quartz 2D API可以实现许多功能,如基于路径的绘图、透明度、阴影、颜色管理、反锯齿、PDF文档生成和PDF元数据访问等

Quartz 2D API是Core Graphics框架的一部分,因此其中的很多数据类型和方法都是以CG开头的。会经常见到Quartz 2D(Quartz)和Core Graphics两个术语交互使用

Quartz 2D与分辨率和设备无关,因此在使用Quartz 2D绘图时,无需考虑最终绘图的目标设备

Core Graphic框架是一组基于C的API,可以用于一切绘图操作,这个框架的重要性,仅次于UIKit和Foundation

当使用UIKit创建按钮、标签或者其他UIView的子类时,UIKit会用Core Graphics将这些元素绘制在屏幕上。此外,UIEvent(UIKit中的事件处理类)也会使用Core Graphics,用来帮助确定触摸事件在屏幕上所处的位置

因为UIKit依赖于Core Graphics,所以当引入<UIKit/Uikit.h>时,Core Graphics框架会被自动引入,即UIKit内部已经引入了Core Graphics框架的主头文件:<CoreGraphics/CoreGraphics.h>

为了让开发者不必触及底层的Core Graphics的C接口,UIKit内部封装了Core Graphics的一些API,可以快速生成通用的界面元素。但是,有时候直接利用Core Graphics的C接口是很有必要和很有好处的,比如创建一个自定义的界面元素。

Quartz 2D绘图的基本步骤:

1. 获取与视图相关联的上下文对象
UIGraphicsGetCurrentContext
2. 创建及设置路径 (path)
2.1 创建路径
2.2 设置路径起点
2.3 增加路径内容……
3. 将路径添加到上下文
4. 设置上下文状态
边线颜色、填充颜色、线宽、线段连接样式、线段首尾样式、虚线样式…
5. 绘制路径
6. 释放路径

接下来实现一个画板:

#import <Foundation/Foundation.h>

@interface DrawPath : NSObject

+ (id)drawPathWithCGPath:(CGPathRef)drawPath
                   color:(UIColor *)color
               lineWidth:(CGFloat)lineWidth;

@property (strong, nonatomic) UIBezierPath *drawPath;
@property (strong, nonatomic) UIColor *drawColor;
@property (assign, nonatomic) CGFloat lineWith;

// 用户选择的图像
@property (strong, nonatomic) UIImage *image;

@end

#import "DrawPath.h"

@implementation DrawPath

+ (id)drawPathWithCGPath:(CGPathRef)drawPath
                   color:(UIColor *)color
               lineWidth:(CGFloat)lineWidth
{
    DrawPath *path = [[DrawPath alloc]init];
    
    path.drawPath = [UIBezierPath bezierPathWithCGPath:drawPath];
    path.drawColor = color;
    path.lineWith = lineWidth;
    
    return path;
}

@end

#import "DrawView.h"
#import "DrawPath.h"

@interface DrawView()

// 当前的绘图路径
@property (assign, nonatomic) CGMutablePathRef drawPath;
// 绘图路径数组
@property (strong, nonatomic) NSMutableArray *drawPathArray;

// 标示路径是否被释放
@property (assign, nonatomic) BOOL pathReleased;

@end

@implementation DrawView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    
    if (self) {
        [self setBackgroundColor:[UIColor whiteColor]];
        
        // 设置属性的初始值
        self.lineWidth = 10.0;
        self.drawColor = [UIColor redColor];
    }
    
    return self;
}

#pragma mark - 绘制视图
// 注意:drawRect方法每次都是完整的绘制视图中需要绘制部分的内容
- (void)drawRect:(CGRect)rect
{
    // 1. 获取上下文
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    [self drawView:context];
}

#pragma mark 绘图视图内容的方法
- (void)drawView:(CGContextRef)context
{
    // 首先将绘图数组中的路径全部绘制出来
    for (DrawPath *path in self.drawPathArray) {
        if (path.image == nil) {
            CGContextAddPath(context, path.drawPath.CGPath);
            
            [path.drawColor set];
            CGContextSetLineWidth(context, path.lineWith);
            
            CGContextSetLineCap(context, kCGLineCapRound);
            
            CGContextDrawPath(context, kCGPathStroke);
        } else {
            // 有图像,没路径
//            CGContextDrawImage(context, self.bounds, path.image.CGImage);
            [path.image drawInRect:self.bounds];
        }
    }
    
    //--------------------------------------------------------
    // 以下代码绘制当前路径的内容,就是手指还没有离开屏幕
    // 内存管理部分提到,所有create创建的都要release,而不能设置成NULL
    if (!self.pathReleased) {        
        // 1. 添加路径
        CGContextAddPath(context, self.drawPath);
        
        // 2. 设置上下文属性
        [self.drawColor set];
        CGContextSetLineWidth(context, self.lineWidth);
        
        CGContextSetLineCap(context, kCGLineCapRound);
        
        // 3. 绘制路径
        CGContextDrawPath(context, kCGPathStroke);
    }
}

#pragma mark - 触摸事件
#pragma mark 触摸开始,创建绘图路径
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInView:self];
    
    self.drawPath = CGPathCreateMutable();
    
    // 记录路径没有被释放
    self.pathReleased = NO;
    
    // 在路径中记录触摸的初始点
    CGPathMoveToPoint(self.drawPath, NULL, location.x, location.y);
}

#pragma mark 移动过程中,将触摸点不断添加到绘图路径
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 可以获取到用户当前触摸的点
    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInView:self];
    
    // 将触摸点添加至路径
    CGPathAddLineToPoint(self.drawPath, NULL, location.x, location.y);
    
    [self setNeedsDisplay];
}

#pragma mark 触摸结束,释放路径
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 一笔画完之后,将完整的路径添加到路径数组之中
    // 使用数组的懒加载
    if (self.drawPathArray == nil) {
        self.drawPathArray = [NSMutableArray array];
    }
    
    // 要将CGPathRef添加到NSArray之中,需要借助贝塞尔曲线对象
    // 贝塞尔曲线是UIKit对CGPathRef的一个封装,贝塞尔路径的对象可以直接添加到数组
//    UIBezierPath *path = [UIBezierPath bezierPathWithCGPath:self.drawPath];
    DrawPath *path = [DrawPath drawPathWithCGPath:self.drawPath color:self.drawColor lineWidth:self.lineWidth];
    
    // 需要记录当前绘制路径的颜色和线宽
    [self.drawPathArray addObject:path];
    
    CGPathRelease(self.drawPath);
    
    // 标示路径已经被释放
    self.pathReleased = YES;
    
    // 测试线宽的代码
//    self.lineWidth = arc4random() % 20 + 1.0;
}

#pragma mark - 工具视图执行方法
- (void)undo
{
    // 在执行撤销操作时,当前没有绘图路径
    // 要做撤销操作,需要把路径数组中的最后一条路径删除
    [self.drawPathArray removeLastObject];
    
    [self setNeedsDisplay];
}

#pragma mark - 清屏操作
- (void)clearScreen
{
    // 在执行清屏操作时,当前没有绘图路径
    // 要做清屏操作,只要把路径数组清空即可
    [self.drawPathArray removeAllObjects];
    
    [self setNeedsDisplay];
}

#pragma mark - image 的 setter方法
- (void)setImage:(UIImage *)image
{
    /*
     目前绘图的方法:
     
     1> 用self.drawPathArray记录已经完成(抬起手指)的路径
     2> 用self.drawPath记录当前正在拖动中的路径
     
     绘制时,首先绘制self.drawPathArray,然后再绘制self.drawPath
     
     image 传入时,drawPath没有被创建(被release但不是NULL)
     
     如果
     1> 我们将image也添加到self.drawPathArray(DrawPath)
     2> 在绘图时,根据是否存在image判断是绘制路径还是图像
     
     就可以实现用一个路径数组即绘制路径,又绘制图像的目的
     
     之所以要用一个数组,是因为绘图是有顺序的
     
     接下来,首先需要扩充DrawPath,使其支持image
     */
    // 1. 实例化一个新的DrawPath
    DrawPath *path = [[DrawPath alloc]init];
    [path setImage:image];
    
    // 2. 将其添加到self.drawPathArray,数组是懒加载的
    if (self.drawPathArray == nil) {
        self.drawPathArray = [NSMutableArray array];
    }
    [self.drawPathArray addObject:path];
    
    // 3. 重绘
    [self setNeedsDisplay];
}

@end
#import <UIKit/UIKit.h>

@interface MyButton : UIButton

@property (assign, nonatomic) BOOL selectedMyButton;

@end
#import "MyButton.h"

@implementation MyButton

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    
    if (self) {
        
        [self.titleLabel setFont:[UIFont systemFontOfSize:12.0]];
        [self setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    }
    
    return self;
}

- (void)drawRect:(CGRect)rect
{
    // 如果selectedMyButton == YES在按钮的下方绘制一条红线
    if (self.selectedMyButton) {
        CGRect frame = CGRectMake(0, self.bounds.size.height - 2, self.bounds.size.width, 2);
        [[UIColor redColor]set];
        UIRectFill(frame);
    }
}

#pragma mark - setter方法
- (void)setSelectedMyButton:(BOOL)selectedMyButton
{
    _selectedMyButton = selectedMyButton;
    
    [self setNeedsDisplay];
}

@end
#import <UIKit/UIKit.h>

#pragma mark - 定义块代码
typedef void(^SelectColorBlock)(UIColor *color);

@interface SelectColorView : UIView

// 扩展initWithFrame方法,增加块代码参数
// 该块代码,将在选择颜色按钮之后执行
- (id)initWithFrame:(CGRect)frame afterSelectColor:(SelectColorBlock)afterSelectColor;

@end
#import "SelectColorView.h"

#define kButtonSpace 10.0

@interface SelectColorView()
{
    // 选择颜色的块代码变量
    SelectColorBlock _selectColorBlock;
}

@property (strong, nonatomic) NSArray *colorArray;

@end

@implementation SelectColorView

- (id)initWithFrame:(CGRect)frame afterSelectColor:(SelectColorBlock)afterSelectColor
{
    self = [super initWithFrame:frame];
    
    if (self) {
        _selectColorBlock = afterSelectColor;
        
        [self setBackgroundColor:[UIColor lightGrayColor]];
        
        // 绘制颜色的按钮
        NSArray *array = @[[UIColor darkGrayColor],
                           [UIColor redColor],
                           [UIColor greenColor],
                           [UIColor blueColor],
                           [UIColor yellowColor],
                           [UIColor orangeColor],
                           [UIColor purpleColor],
                           [UIColor brownColor],
                           [UIColor blackColor],
                           ];
        self.colorArray = array;
        
        [self createColorButtonsWithArray:array];
    }
    
    return self;
}

#pragma mark - 绘制颜色按钮
- (void)createColorButtonsWithArray:(NSArray *)array
{
    // 1. 计算按钮的位置
    // 2. 设置按钮的颜色,需要使用数组
    // 按钮的宽度,起始点位置
    NSInteger count = array.count;
    CGFloat width = (self.bounds.size.width - (count + 1) * kButtonSpace)/ count;
    CGFloat height = self.bounds.size.height;
    
    NSInteger index = 0;
    for (NSString *text in array) {
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        
        CGFloat startX = kButtonSpace + index * (width + kButtonSpace);
        [button setFrame:CGRectMake(startX, 5, width, height - 10)];
        
        // 设置按钮的背景颜色
        [button setBackgroundColor:array[index]];
        [button setTag:index];
        
        [button addTarget:self action:@selector(tapButton:) forControlEvents:UIControlEventTouchUpInside];
        
        [self addSubview:button];
        
        index++;
    }
}

#pragma mark - 按钮监听方法
- (void)tapButton:(UIButton *)button
{
    // 调用块代码
    _selectColorBlock(self.colorArray[button.tag]);
}

@end
#import <UIKit/UIKit.h>

#pragma mark - 定义块代码
typedef void(^SelectLineWidthBlock)(CGFloat lineWidth);

@interface SelectLineWidthView : UIView

#pragma mark 扩展初始化方法,增加块代码
- (id)initWithFrame:(CGRect)frame afterSelectLineWidth:(SelectLineWidthBlock)afterSeletLineWidth;

@end
#import "SelectLineWidthView.h"
// 针对不同的界面,因为按钮的数量是不同的,有时候需要调整按钮间距,保证好的视觉效果
#define kButtonSpace 10.0

@interface SelectLineWidthView()
{
    SelectLineWidthBlock _selectLineWidthBlock;
}

@property (strong, nonatomic) NSArray *lineWidthArray;

@end

@implementation SelectLineWidthView

- (id)initWithFrame:(CGRect)frame afterSelectLineWidth:(SelectLineWidthBlock)afterSeletLineWidth
{
    self = [super initWithFrame:frame];
    if (self) {
        _selectLineWidthBlock = afterSeletLineWidth;
        
        [self setBackgroundColor:[UIColor redColor]];
        
        [self setBackgroundColor:[UIColor lightGrayColor]];
        
        // 绘制颜色的按钮
        NSArray *array = @[@(1.0), @(3.0), @(5.0), @(8.0), @(10.0), @(15.0), @(20.0)
                           ];
        self.lineWidthArray = array;
        
        [self createLineButtonsWithArray:array];
    }
    return self;
}

#pragma mark 创建选择线宽的按钮
- (void)createLineButtonsWithArray:(NSArray *)array
{
    // 1. 计算按钮的位置
    // 2. 设置按钮的颜色,需要使用数组
    // 按钮的宽度,起始点位置
    NSInteger count = array.count;
    CGFloat width = (self.bounds.size.width - (count + 1) * kButtonSpace)/ count;
    CGFloat height = self.bounds.size.height;
    
    NSInteger index = 0;
    for (NSString *text in array) {
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        
        CGFloat startX = kButtonSpace + index * (width + kButtonSpace);
        [button setFrame:CGRectMake(startX, 5, width, height - 10)];
        
        // 设置选择线宽的提示文字
        NSString *text = [NSString stringWithFormat:@"%@点", self.lineWidthArray[index]];
        [button setTitle:text forState:UIControlStateNormal];
        
        [button.titleLabel setFont:[UIFont systemFontOfSize:15]];
        
        [button setTag:index];
        
        [button addTarget:self action:@selector(tapButton:) forControlEvents:UIControlEventTouchUpInside];
        
        [self addSubview:button];
        
        index++;
    }
}

#pragma mark - 按钮监听方法
- (void)tapButton:(UIButton *)button
{
    // 把按钮对应的线宽数值作为块代码的参数,执行块代码
    _selectLineWidthBlock([self.lineWidthArray[button.tag]floatValue]);
}

@end
#import <UIKit/UIKit.h>
#import "SelectColorView.h"
#import "SelectLineWidthView.h"

#pragma mark 工具视图的操作块代码
typedef void(^ToolViewActionBlock)();

//#pragma mark - 选择橡皮擦的块代码定义
//typedef void(^ToolViewSelectEarserBlock)();
//#pragma mark - 选择撤销操作的块代码
//typedef void(^ToolViewSelectUndoBlock)();
//#pragma mark - 选择清屏操作的块代码
//typedef void(^ToolViewSelectClearBlock) ();
//#pragma mark - 选择相机的块代码
//typedef void(^ToolViewSelectPhotoBlock) ();

@interface ToolView : UIView

// 对initWithFrame进行扩展,增加块代码参数
- (id)initWithFrame:(CGRect)frame
afterSelectColor:(SelectColorBlock)afterSelectColor
afterSelectLineWidth:(SelectLineWidthBlock)afterSelectLineWidth
       selectEarser:(ToolViewActionBlock)selectEarser
          seletUndo:(ToolViewActionBlock)selectUndo
        selectClear:(ToolViewActionBlock)selectClear
        selectPhoto:(ToolViewActionBlock)selectPhoto;

@end
#import "ToolView.h"
#import "MyButton.h"

// 按钮的间距
#define kButtonSpace 10.0

// 注意,枚举的顺序需要和按钮文字数组中的顺序保持一致
typedef enum
{
    kButtonColor = 0,
    kButtonLineWidth,
    kButtonEarser,
    kButtonUndo,
    kButtonClearScreen,
    kButtonCamera,
    kButtonSave
} kButtonActionType;

@interface ToolView()
{
    SelectColorBlock _selectColorBlock;
    SelectLineWidthBlock _selectLineWidthBlock;
    ToolViewActionBlock _selectEarserBlock;
    ToolViewActionBlock _selectUndoBlock;
    ToolViewActionBlock _selectClearBlock;
    ToolViewActionBlock _selectPhotoBlock;
}

// 当前用户选中的按钮
@property (weak, nonatomic) MyButton *selectButton;
// 选择颜色视图
@property (weak, nonatomic) SelectColorView *colorView;
// 选择线宽视图
@property (weak, nonatomic) SelectLineWidthView *lineWidthView;

@end

@implementation ToolView

- (id)initWithFrame:(CGRect)frame
   afterSelectColor:(SelectColorBlock)afterSelectColor
afterSelectLineWidth:(SelectLineWidthBlock)afterSelectLineWidth
       selectEarser:(ToolViewActionBlock)selectEarser
          seletUndo:(ToolViewActionBlock)selectUndo
        selectClear:(ToolViewActionBlock)selectClear
        selectPhoto:(ToolViewActionBlock)selectPhoto
{
    self = [super initWithFrame:frame];
    
    if (self) {
        _selectColorBlock = afterSelectColor;
        _selectLineWidthBlock = afterSelectLineWidth;
        _selectEarserBlock = selectEarser;
        _selectUndoBlock = selectUndo;
        _selectClearBlock = selectClear;
        _selectPhotoBlock = selectPhoto;
        
        [self setBackgroundColor:[UIColor lightGrayColor]];
        
        // 通过循环的方式创建按钮
        NSArray *array = @[@"颜色", @"线宽", @"橡皮", @"撤销", @"清屏", @"相机", @"保存"];
        
        [self createButtonsWithArray:array];
    }
    
    return self;
}

#pragma mark 创建工具视图中的按钮
- (void)createButtonsWithArray:(NSArray *)array
{
    // 按钮的宽度,起始点位置
    NSInteger count = array.count;
    CGFloat width = (self.bounds.size.width - (count + 1) * kButtonSpace)/ count;
    CGFloat height = self.bounds.size.height;
    
    NSInteger index = 0;
    for (NSString *text in array) {        
        MyButton *button = [MyButton buttonWithType:UIButtonTypeCustom];
        
        CGFloat startX = kButtonSpace + index * (width + kButtonSpace);
        [button setFrame:CGRectMake(startX, 8, width, height - 16)];
        
        [button setTitle:text forState:UIControlStateNormal];
        [button setTag:index];
        
        [button addTarget:self action:@selector(tapButton:) forControlEvents:UIControlEventTouchUpInside];
        
        [self addSubview:button];
        
        // 测试代码
//        [button setSelectedMyButton:YES];
        
        index++;
    }
}

#pragma mark 按钮监听方法
- (void)tapButton:(MyButton *)button
{
    // 方法1:遍历所有的按钮,将selectedMyButton设置为NO,取消所有的下方红线
    // 方法2:在属性中记录前一次选中的按钮,将该按钮的属性设置为NO
    if (self.selectButton != nil && self.selectButton != button) {
        [self.selectButton setSelectedMyButton:NO];
    }
    // 通过设置当前按钮selectedMyButton属性,在下方绘制红线
    [button setSelectedMyButton:YES];
    self.selectButton = button;
    
    switch (button.tag) {
        case kButtonColor:
            // 点击按钮的时候强行关闭当前显示的子视图
            [self forceHideView:self.colorView];
            
            // 显示/隐藏颜色选择视图
            [self showHideColorView];
            
            break;
        case kButtonLineWidth:
            // 点击按钮的时候强行关闭当前显示的子视图
            [self forceHideView:self.lineWidthView];
            
            // 显示/隐藏选择线宽视图
            [self showHideLineWidthView];
            
            break;
        case kButtonEarser:
            // 以变量的方式调用视图控制器的块代码
            _selectEarserBlock();
            
            [self forceHideView:nil];
            
            break;
        case kButtonUndo:
            _selectUndoBlock();
            
            [self forceHideView:nil];
            
            break;
        case kButtonClearScreen:
            _selectClearBlock();
            
            [self forceHideView:nil];
            
            break;
        case kButtonCamera:
            _selectPhotoBlock();
            
            [self forceHideView:nil];
            
            break;
        default:
            break;
    }
}

#pragma mark - 子视图操作方法
#pragma mark 强行隐藏当前显示的子视图
// 如果显示的视图与传入的比较视图相同,就不再关闭
- (void)forceHideView:(UIView *)compareView
{
    // 1. 用属性记录当前显示的子视图,强行关闭该视图即可
    // 2. 遍历所有子视图,如果处于显示状态,则将其关闭
    // 3. 直接判断子视图,此方法仅适用于子数图数量极少
    UIView *view = nil;
    if (self.colorView.frame.origin.y > 0) {
        view = self.colorView;
    } else if (self.lineWidthView.frame.origin.y > 0) {
        view = self.lineWidthView;
    } else {
        return;
    }
    
    if (view == compareView) {
        return;
    }
    
    CGRect toFrame = view.frame;
    CGRect toolFrame = self.frame;
    
    toFrame.origin.y = -44;
    toolFrame.size.height = 44;
    
    [UIView animateWithDuration:0.5f animations:^{
        [self setFrame:toolFrame];
        [view setFrame:toFrame];
    }];
}

#pragma mark 显示隐藏指定视图
- (void)showHideView:(UIView *)view
{
    // 2. 动画显示颜色视图
    CGRect toFrame = view.frame;
    // 工具条视图边框
    CGRect toolFrame = self.frame;
    if (toFrame.origin.y < 0) {
        // 隐藏的我们显示
        toFrame.origin.y = 44;
        toolFrame.size.height = 88;
    } else {
        toFrame.origin.y = -44;
        toolFrame.size.height = 44;
    }
    
    [UIView animateWithDuration:0.5f animations:^{
        [self setFrame:toolFrame];
        [view setFrame:toFrame];
    }];
}

#pragma mark 显示隐藏选择线宽视图
- (void)showHideLineWidthView
{
    // 1. 懒加载选择线宽视图
    if (self.lineWidthView == nil) {
        SelectLineWidthView *view = [[SelectLineWidthView alloc]initWithFrame:CGRectMake(0, -44, 320, 44) afterSelectLineWidth:^(CGFloat lineWidth) {
            
            NSLog(@"%f", lineWidth);
            
            _selectLineWidthBlock(lineWidth);
            
            // 强行关闭线宽选择子视图
            [self forceHideView:nil];
        }];
    
        [self addSubview:view];
        
        self.lineWidthView = view;
    }
   
    [self showHideView:self.lineWidthView];
}

#pragma mark 显示隐藏颜色视图
- (void)showHideColorView
{
    // 1. 懒加载颜色视图
    if (self.colorView == nil) {
        SelectColorView *view = [[SelectColorView alloc]initWithFrame:CGRectMake(0, -44, 320, 44) afterSelectColor:^(UIColor *color) {
            
            // 以函数的方式调用块代码变量
            _selectColorBlock(color);
            
            // 选中颜色后,强行关闭颜色选择子视图
            [self forceHideView:nil];
            
            NSLog(@"aaah");
        }];
        
        [self addSubview:view];
        
        self.colorView = view;
    }

    [self showHideView:self.colorView];
}


@end
#import "MainViewController.h"
#import "DrawView.h"
#import "ToolView.h"

@interface MainViewController ()

@property (weak, nonatomic) DrawView *drawView;

@end

@implementation MainViewController

#pragma mark - 实例化视图
- (void)loadView
{
    self.view = [[UIView alloc]initWithFrame:[UIScreen mainScreen].applicationFrame];;

    DrawView *drawView = [[DrawView alloc]initWithFrame:self.view.bounds];
    [self.view addSubview:drawView];
    self.drawView = drawView;
    
    ToolView *toolView = [[ToolView alloc]initWithFrame:CGRectMake(0, 0, 320, 44) afterSelectColor:^(UIColor *color) {

        // 给绘图视图设置颜色
        [drawView setDrawColor:color];
    } afterSelectLineWidth:^(CGFloat lineWidth) {
        // 工具视图选择线宽之后,需要执行的代码
        [drawView setLineWidth:lineWidth];
    } selectEarser:^{
        [drawView setDrawColor:[UIColor whiteColor]];
        [drawView setLineWidth:30.0];
    } seletUndo:^{
        [drawView undo];
    } selectClear:^{
        [drawView clearScreen];
    } selectPhoto:^{
        // 弹出图像选择窗口,来选择照片
        UIImagePickerController *picker = [[UIImagePickerController alloc]init];
        
        // 1. 设置照片源
        [picker setSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
        // 2. 设置代理
        [picker setDelegate:self];
        
        // 3. 显示
        [self presentViewController:picker animated:YES completion:nil];
    }];
    
    [self.view addSubview:toolView];
}

#pragma mark - 照片选择代理方法
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    UIImage *image = info[@"UIImagePickerControllerOriginalImage"];
    
    // 设置绘图视图
    [self.drawView setImage:image];

    // 关闭照片选择窗口
    [self dismissViewControllerAnimated:YES completion:nil];
}

@end

转载于:https://my.oschina.net/khakiloveyty/blog/396543

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值