首页 > 代码库 > [iOS UI进阶 - 4.0] 涂鸦app Demo

[iOS UI进阶 - 4.0] 涂鸦app Demo

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 =http://www.mamicode.com/ 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 @optional15 - (void) selectColor:(UIColor *) selectedColor;16 17 @end18 19 @interface ColorSelectionView : UIView20 21 /** 代理 */22 @property(nonatomic, strong) id<ColorSelectionViewDelegate> delegate;23 24 @end25  26 //27 //  ColorSelectionView.m28 //  PaintDemo29 //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 ColorSelectionView37 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 : UIBezierPath12 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 @end26 27 @implementation ViewController28 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

 

 

[iOS UI进阶 - 4.0] 涂鸦app Demo