A.需求
1.超简易画图,只有一种画笔
2.清屏功能
3.回退功能
4.保存功能
5.使用了cocos2D
code source: https://github.com/hellovoidworld/PaintDemo
B.实现方法1
1.基本界面
(1)3个按钮:清屏、回退、保存
(2)绘图view
2.画线
(1)使用数组存储绘图点:存储一条线的数组、存储所有线的总数组
(2)在touch的开始、拖曳、结束记录触摸位置,触发重绘
3.清屏
删除总数组
4.回退
删除最后画的一条线:删除相应数组
5.保存到相册
使用”截图”功能,保存绘图view
1 // 2 // PaintView.m 3 // PaintDemo 4 // 5 // Created by hellovoidworld on 15/1/10. 6 // Copyright (c) 2015年 hellovoidworld. All rights reserved. 7 // 8 9 #import "PaintView.h" 10 #import "UIImage+Extension.h" 11 12 @interface PaintView() 13 14 @end 15 16 @implementation PaintView 17 18 - (NSMutableArray *)lines { 19 if (nil == _lines) { 20 _lines = [NSMutableArray array]; 21 } 22 return _lines; 23 } 24 25 #pragma mark - 触摸事件 26 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 27 UITouch *touch = [touches anyObject]; 28 CGPoint startLocation = [touch locationInView:touch.view]; 29 30 // 开启一条新的线 31 NSMutableArray *points = [NSMutableArray array]; 32 // 存储点信息到线上 33 [points addObject:[NSValue valueWithCGPoint:startLocation]]; 34 // 存储到线组上 35 [self.lines addObject:points]; 36 37 // 重绘 38 [self setNeedsDisplay]; 39 } 40 41 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { 42 UITouch *touch = [touches anyObject]; 43 CGPoint location = [touch locationInView:touch.view]; 44 45 // 拿到正在画的线 46 NSMutableArray *points = [self.lines lastObject]; 47 // 添加点信息 48 [points addObject:[NSValue valueWithCGPoint:location]]; 49 50 // 重绘 51 [self setNeedsDisplay]; 52 } 53 54 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { 55 // 停止拖曳的逻辑其实和拖曳中是一样的 56 [self touchesMoved:touches withEvent:event]; 57 } 58 59 #pragma mark - 绘图方法 60 /** 绘图 */ 61 - (void)drawRect:(CGRect)rect { 62 CGContextRef ctx = UIGraphicsGetCurrentContext(); 63 64 // 遍历线组,把所有线画出来 65 for (NSArray *line in self.lines) { 66 for (int i=0; i<line.count; i++) { 67 NSValue *pointValue = line[i]; 68 CGPoint point = [pointValue CGPointValue]; 69 70 // 如果是线的第一个点,要先移动画笔到那个点 71 if (0 == i) { 72 CGContextMoveToPoint(ctx, point.x, point.y); 73 } else { 74 CGContextAddLineToPoint(ctx, point.x, point.y); 75 } 76 } 77 } 78 79 // 设置线宽、线头样式、线转折样式 80 CGContextSetLineWidth(ctx, 5); 81 CGContextSetLineCap(ctx, kCGLineCapRound); 82 CGContextSetLineJoin(ctx, kCGLineJoinRound); 83 84 // 渲染 85 CGContextStrokePath(ctx); 86 } 87 88 #pragma mark - view操作方法 89 /** 回退 */ 90 - (void)rollback { 91 [self.lines removeLastObject]; 92 [self setNeedsDisplay]; 93 } 94 95 /** 清屏 */ 96 - (void)clearScreen { 97 [self.lines removeAllObjects]; 98 [self setNeedsDisplay]; 99 } 100 101 /** 保存 */ 102 - (void)save { 103 // 1.获取图片 104 UIImage *image = [UIImage imageOfView:self]; 105 106 // 2.保存图片到相册 107 UIImageWriteToSavedPhotosAlbum(image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil); 108 } 109 110 /** 保存图片后激发事件 111 * 这是文档推荐的方法 112 */ 113 - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo { 114 if (error) { 115 NSLog(@"保存失败"); 116 } else { 117 NSLog(@"保存成功"); 118 } 119 } 120 121 @end
1 // 2 // UIImage+Extension.m 3 // PaintDemo 4 // 5 // Created by hellovoidworld on 15/1/11. 6 // Copyright (c) 2015年 hellovoidworld. All rights reserved. 7 // 8 9 #import "UIImage+Extension.h" 10 11 @implementation UIImage(Extension) 12 13 + (UIImage *) imageOfView:(UIView *) view { 14 // 1.开启图片上下文 15 UIGraphicsBeginImageContextWithOptions(view.frame.size, NO, 0.0); 16 17 // 2.将view的layer渲染到上下文 18 [view.layer renderInContext:UIGraphicsGetCurrentContext()]; 19 20 // 3.获取上下文中的图片 21 UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 22 23 // 4.关闭图片上下文 24 UIGraphicsEndImageContext(); 25 26 return image; 27 } 28 29 @end
C.实现方法2
1.基本界面和方法1一样
2.画线
(1)使用贝塞尔路径UIBezierPath,一条线就是一个UIBezierPath对象
(2)同样使用数组来存储UIBezierPath对象
3.清屏、回退、保存和方法1一样
1 // 2 // BezierPaintView.m 3 // PaintDemo 4 // 5 // Created by hellovoidworld on 15/1/11. 6 // Copyright (c) 2015年 hellovoidworld. All rights reserved. 7 // 8 9 #import "BezierPaintView.h" 10 #import "UIImage+Extension.h" 11 12 @implementation BezierPaintView 13 14 - (NSMutableArray *)lines { 15 if (nil == _lines) { 16 _lines = [NSMutableArray array]; 17 } 18 return _lines; 19 } 20 21 #pragma mark - 触摸事件 22 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 23 UITouch *touch = [touches anyObject]; 24 CGPoint startLocation = [touch locationInView:touch.view]; 25 26 // 新建一条Bezier线 27 UIBezierPath *path = [UIBezierPath bezierPath]; 28 [path setLineWidth:5.0]; 29 [path setLineCapStyle:kCGLineCapRound]; 30 [path setLineJoinStyle:kCGLineJoinRound]; 31 32 // 移动到始点 33 [path moveToPoint:startLocation]; 34 // 添加Bezier线到数组 35 [self.lines addObject:path]; 36 37 // 重绘 38 [self setNeedsDisplay]; 39 } 40 41 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { 42 UITouch *touch = [touches anyObject]; 43 CGPoint location = [touch locationInView:touch.view]; 44 45 // 获得正在画的线 46 UIBezierPath *path = [self.lines lastObject]; 47 // 画线-添加点信息 48 [path addLineToPoint:location]; 49 50 // 重绘 51 [self setNeedsDisplay]; 52 } 53 54 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { 55 // 停止拖曳的逻辑其实和拖曳中是一样的 56 [self touchesMoved:touches withEvent:event]; 57 } 58 59 #pragma mark - 绘图方法 60 /** 绘图 */ 61 - (void)drawRect:(CGRect)rect { 62 63 // 画出所有的线 64 for (UIBezierPath *path in self.lines) { 65 // 渲染 66 [path stroke]; 67 } 68 69 } 70 71 #pragma mark - view操作方法 72 /** 回退 */ 73 - (void)rollback { 74 [self.lines removeLastObject]; 75 [self setNeedsDisplay]; 76 } 77 78 /** 清屏 */ 79 - (void)clearScreen { 80 [self.lines removeAllObjects]; 81 [self setNeedsDisplay]; 82 } 83 84 /** 保存 */ 85 - (void)save { 86 // 1.获取图片 87 UIImage *image = [UIImage imageOfView:self]; 88 89 // 2.保存图片到相册 90 UIImageWriteToSavedPhotosAlbum(image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil); 91 } 92 93 /** 保存图片后激发事件 94 * 这是文档推荐的方法 95 */ 96 - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo { 97 if (error) { 98 NSLog(@"保存失败"); 99 } else { 100 NSLog(@"保存成功"); 101 } 102 } 103 104 @end
D.附加功能
- slider控件调整线宽
- 选择颜色
1.slider调整线宽
(1)使用slider控件
(2)通过slider的valueChange事件调用方法设置线宽
2.选择颜色
(1)创建一个“色块”类
- 使用UIView作为色块
- 自定义一个继承UIView的类,作为色块class,给色块UIView加上点击事件
- 给色块UIView创建一个颜色属性和代理协议,代理是ViewController;创建一个点击代理事件方法
1 // 2 // ColorSelectionView.h 3 // PaintDemo 4 // 5 // Created by hellovoidworld on 15/1/11. 6 // Copyright (c) 2015年 hellovoidworld. All rights reserved. 7 // 8 9 #import <UIKit/UIKit.h> 10 11 @protocol ColorSelectionViewDelegate <NSObject> 12 13 /** “色块”点击代理方法 */ 14 @optional 15 - (void) selectColor:(UIColor *) selectedColor; 16 17 @end 18 19 @interface ColorSelectionView : UIView 20 21 /** 代理 */ 22 @property(nonatomic, strong) id<ColorSelectionViewDelegate> delegate; 23 24 @end 25 26 // 27 // ColorSelectionView.m 28 // PaintDemo 29 // 30 // Created by hellovoidworld on 15/1/11. 31 // Copyright (c) 2015年 hellovoidworld. All rights reserved. 32 // 33 34 #import "ColorSelectionView.h" 35 36 @implementation ColorSelectionView 37 38 - (void)awakeFromNib { 39 // 给UIView设置点击事件 40 UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(colorClicked)]; 41 [self addGestureRecognizer:tapGesture]; 42 } 43 44 /** “色块”点击事件 */ 45 - (void) colorClicked { 46 [self.delegate selectColor:self.backgroundColor]; 47 } 48 49 @end
(2)自定义一个继承UIBezierPath的类,增加一个线颜色的属性
1 // 2 // HVWBezierPath.h 3 // PaintDemo 4 // 5 // Created by hellovoidworld on 15/1/11. 6 // Copyright (c) 2015年 hellovoidworld. All rights reserved. 7 // 8 9 #import <UIKit/UIKit.h> 10 11 @interface HVWBezierPath : UIBezierPath 12 13 /** 颜色 */ 14 @property(nonatomic, strong) UIColor *color; 15 16 @end
(3)ViewController代理“色块”的点击事件
- 拖入所有“色块”对象到ViewController,设置代理
- 遵守“色块”协议,实现代理方法
1 // 2 // ViewController.m 3 // PaintDemo 4 // 5 // Created by hellovoidworld on 15/1/10. 6 // Copyright (c) 2015年 hellovoidworld. All rights reserved. 7 // 8 9 #import "ViewController.h" 10 #import "BezierPaintView.h" 11 #import "ColorSelectionView.h" 12 13 @interface ViewController () <ColorSelectionViewDelegate> 14 15 @property (weak, nonatomic) IBOutlet BezierPaintView *paintView; 16 17 /** 颜色选择集合 */ 18 @property (strong, nonatomic) IBOutletCollection(ColorSelectionView) NSArray *colorSelection; 19 20 - (IBAction)rollback; 21 - (IBAction)clearScreen; 22 - (IBAction)save; 23 - (IBAction)lineWidthChange:(UISlider *)sender; 24 25 @end 26 27 @implementation ViewController 28 29 - (void)viewDidLoad { 30 [super viewDidLoad]; 31 // Do any additional setup after loading the view, typically from a nib. 32 33 // 设置颜色选择器的代理 34 for (ColorSelectionView *colorView in self.colorSelection) { 35 colorView.delegate = self; 36 } 37 } 38 39 - (void)didReceiveMemoryWarning { 40 [super didReceiveMemoryWarning]; 41 // Dispose of any resources that can be recreated. 42 } 43 44 /** 回退 */ 45 - (IBAction)rollback { 46 [self.paintView rollback]; 47 } 48 49 /** 清屏 */ 50 - (IBAction)clearScreen { 51 [self.paintView clearScreen]; 52 } 53 54 /** 保存 */ 55 - (IBAction)save { 56 [self.paintView save]; 57 } 58 59 /** 改变线粗 */ 60 - (IBAction)lineWidthChange:(UISlider *)sender { 61 self.paintView.lineWidth = sender.value; 62 } 63 64 #pragma mark - ColorSelectionViewDelegate 代理方法 65 - (void) selectColor:(UIColor *) selectedColor { 66 self.paintView.lineColor = selectedColor; 67 }
@end
(4)“画板”在开始画一条线的时候(触摸开始),设置线宽和颜色
1 // 2 // BezierPaintView.m 3 // PaintDemo 4 // 5 // Created by hellovoidworld on 15/1/11. 6 // Copyright (c) 2015年 hellovoidworld. All rights reserved. 7 // 8 9 #import "BezierPaintView.h" 10 #import "UIImage+Extension.h" 11 #import "HVWBezierPath.h" 12 13 @interface BezierPaintView() 14 15 @end 16 17 @implementation BezierPaintView 18 19 - (NSMutableArray *)lines { 20 if (nil == _lines) { 21 _lines = [NSMutableArray array]; 22 } 23 return _lines; 24 } 25 26 #pragma mark - 触摸事件 27 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 28 UITouch *touch = [touches anyObject]; 29 CGPoint startLocation = [touch locationInView:touch.view]; 30 31 // 新建一条Bezier线 32 HVWBezierPath *path = [[HVWBezierPath alloc] init]; 33 34 // 配置线粗 35 if (self.lineWidth) { 36 [path setLineWidth:self.lineWidth]; 37 } 38 39 // 配置线色 40 if (self.lineColor) { 41 path.color = self.lineColor; 42 } 43 44 [path setLineCapStyle:kCGLineCapRound]; 45 [path setLineJoinStyle:kCGLineJoinRound]; 46 47 // 移动到始点 48 [path moveToPoint:startLocation]; 49 // 添加Bezier线到数组 50 [self.lines addObject:path]; 51 52 // 重绘 53 [self setNeedsDisplay]; 54 } 55 56 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { 57 UITouch *touch = [touches anyObject]; 58 CGPoint location = [touch locationInView:touch.view]; 59 60 // 获得正在画的线 61 HVWBezierPath *path = [self.lines lastObject]; 62 // 画线-添加点信息 63 [path addLineToPoint:location]; 64 65 // 重绘 66 [self setNeedsDisplay]; 67 } 68 69 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { 70 // 停止拖曳的逻辑其实和拖曳中是一样的 71 [self touchesMoved:touches withEvent:event]; 72 } 73 74 #pragma mark - 绘图方法 75 /** 绘图 */ 76 - (void)drawRect:(CGRect)rect { 77 78 // 画出所有的线 79 for (HVWBezierPath *path in self.lines) { 80 81 // 设置颜色 82 if (path.color) { 83 [path.color set]; 84 } 85 86 // 渲染 87 [path stroke]; 88 } 89 90 } 91 92 #pragma mark - view操作方法 93 /** 回退 */ 94 - (void)rollback { 95 [self.lines removeLastObject]; 96 [self setNeedsDisplay]; 97 } 98 99 /** 清屏 */ 100 - (void)clearScreen { 101 [self.lines removeAllObjects]; 102 [self setNeedsDisplay]; 103 } 104 105 /** 保存 */ 106 - (void)save { 107 // 1.获取图片 108 UIImage *image = [UIImage imageOfView:self]; 109 110 // 2.保存图片到相册 111 UIImageWriteToSavedPhotosAlbum(image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil); 112 } 113 114 /** 保存图片后激发事件 115 * 这是文档推荐的方法 116 */ 117 - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo { 118 if (error) { 119 NSLog(@"保存失败"); 120 } else { 121 NSLog(@"保存成功"); 122 } 123 } 124 125 126 @end