响应者对象:继承了UIResponder的对象

触摸事件:一根或多根手指;
开始触摸:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;

移动:每移动一点就会调用一次;

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;

触摸结束:

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;

触摸事件被打断:

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;

远程控制事件:

- (void)remoteControlReceivedWithEvent:(UIEvent *)event NS_AVAILABLE_IOS(4_0);

UIToch对象:

触摸时,会为每个手指创建一个相关联的UITouch对象,保存着跟手指相关的信息,触摸的位置、时间等;

手指移动时,系统会更新同一个UITouch对象,一直保存手指触摸的位置;

手指移开时,销毁UITouch;

获取touch对象:UITouch * touch = [touches anyObject];

触摸点所在的view

touch.view

触摸点所在的window

touch.window

获取当前触摸点的位置,相对于哪个view的位置,填nil为相对于window;

CGPoint point = [touch locationInView:touch.view];

获取上一个触摸点的位置,可以用于touchesMoved方法中

CGPoint point2 = [touch previousLocationInView:touch.view];

效果图:

         画笔笔头根据画笔宽度进行改变:

原理:利用view的触摸事件,使用UIBezierPath对象进行涂鸦,UIBezierPath可以储存线段上的所有点,当成一条路径使用,并且被渲染到视图上;根据触摸点位置变化设置跟踪笔头;

我仅仅实现了效果,封装的不是很好完善,推荐这位大神的博客,封装思想很好点击这里

我有一个继承自UIView的tuyaView来作为白色涂鸦板,一个设置画笔属性的UIViewController,一个用于储存画笔属性的数据manager类;

图片

步骤:

涂鸦板view:

1、自定义一个继承自UIView的view作为涂鸦板,UIView继承自UIResponder,可以接收触摸事件; 声明三个数组属性用于存放线段以及线段属性,并且在懒加载中初始化;

2、在view的touchBegin事件中,新建一个UIBezierPath对象,使用它的moveToPoint方法将当前的触摸点设为这条线段的起点,并且将他存放到我们的线段数组中,从数据管理器中拿出线段的各种属性存放在属性数组中。初始化圆形画笔笔头,添加到涂鸦板上,中心位为触摸点;

4、监控手指的移动,将剩余线段点加入到上面创建的UIBezierPath对象中;从数组中取出贝塞尔对象,使用它的addLineToPoint方法,将移动后得到的当前点储存上;并且调用view的setNeedDisplay方法,重绘view;设置画笔笔头跟踪手指触摸移动。当触摸结束时,将笔头view移除;

5、实现view的drawRect方法:此方法用于绘制view,第四步设置了每当touchmove时都会调用此方法,从数组中拿出每一个贝塞尔对象,将它画到view上,并且取出相应的画笔样式;如果用户选取了照片就将照片绘制上去,这样绘制功能就实现了;

6、实现添加图片、退一步、清空画布、保存图片四个方法;

tuyaView.m

 @interface tuyaView ()
保存每条线段
@property (nonatomic, strong) NSMutableArray * linePaths;
保存每条线段的画笔大小
@property (nonatomic, strong) NSMutableArray * penValues;
保存每条线段颜色
@property (nonatomic, strong) NSMutableArray * penColors;
数据管理器
@property (nonatomic, strong) manager * m;
画笔 笔头;
@property (nonatomic, strong) UIView * touchPointView; @end @implementation tuyaView
懒加载中初始化各个数组
-(manager *)m
{
if (!_m)
{
_m = [manager shared];
}
return _m;
} -(NSMutableArray *)penValues
{
if (!_penValues)
{
_penValues = [NSMutableArray array];
}
return _penValues;
} - (NSMutableArray *)linePaths
{
if (!_linePaths) {
_linePaths = [NSMutableArray array];
}
return _linePaths;
} -(NSMutableArray *)penColors
{
if (!_penColors) {
_penColors = [NSMutableArray array];
}
return _penColors;
} 触摸事件开始
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch * touch = [touches anyObject];
CGPoint point = [touch locationInView:touch.view];
//
UIBezierPath * linePath = [UIBezierPath bezierPath];
[linePath moveToPoint:point];
[self.linePaths addObject:linePath]; //保存线条粗细
float penValue = self.m.penValue;
[self.penValues addObject:[NSNumber numberWithFloat:penValue ]];
//保存线条颜色
UIColor * penColor = self.m.penColor;
[self.penColors addObject:penColor]; //创建触控点
CGFloat touchRadius = self.m.penValue + ;
self.touchPointView = [[UIView alloc] initWithFrame:CGRectMake(point.x - touchRadius * 0.5, point.y - touchRadius * 0.5, touchRadius, touchRadius)];
self.touchPointView.layer.cornerRadius = touchRadius * 0.5;
self.touchPointView.clipsToBounds = YES;
self.touchPointView.backgroundColor = [UIColor redColor];
self.touchPointView.alpha = 0.5;
[self addSubview:self.touchPointView];
} 手指移动
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch * touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:touch.view]; UIBezierPath * linePath = [self.linePaths lastObject];
[linePath addLineToPoint:touchPoint]; //触控点移动
CGPoint current = [touch locationInView:touch.view];
CGPoint pre = [touch previousLocationInView:touch.view];
CGPoint center = self.touchPointView.center;
center.x += current.x - pre.x;
center.y += current.y - pre.y;
self.touchPointView.center = center; [self setNeedsDisplay];
} 触摸结束
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.touchPointView removeFromSuperview];
} 绘制view
-(void)drawRect:(CGRect)rect
{
[self.tuyaImage drawInRect:CGRectMake(, , rect.size.width, rect.size.height)]; for (int i = ; i < self.linePaths.count; i ++)
{
UIBezierPath * path = self.linePaths[i];
//取出线条宽度
float penValue = [self.penValues[i] floatValue];
[path setLineWidth:penValue];
//取出线条颜色
UIColor * color = self.penColors[i];
[color setStroke]; [path setLineJoinStyle:kCGLineJoinRound];
[path setLineCapStyle:kCGLineCapRound];
[path stroke];
}
} 选取图片
- (void)fetchPictureWith:(UIImage *)image
{
self.tuyaImage = image;
[self setNeedsDisplay];
} 退后一步
- (void)backTheLastTime
{
[self.linePaths removeLastObject];
[self.penValues removeLastObject];
[self.penColors removeLastObject];
[self setNeedsDisplay];
} 清空画布
- (void)cleanAllPainted
{
[self.linePaths removeAllObjects];
[self.penValues removeAllObjects];
[self.penColors removeAllObjects];
self.tuyaImage = nil;
[self setNeedsDisplay];
} 保存图片到手机相册
- (void)savePicture
{
//1、开启上下文
UIGraphicsBeginImageContextWithOptions(self.frame.size, YES, 0.0);
//2、将控制器view的layer渲染到上下文,想要截啥就把哪个图层拿出来渲染
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
//3、取出图片
UIImage * newImage = UIGraphicsGetImageFromCurrentImageContext();
//保存到手机相册
UIImageWriteToSavedPhotosAlbum(newImage, nil, nil, nil);
//关闭上下文
UIGraphicsEndImageContext();
}

属性控制器:1、从数据管理器中取出数据显示到自身view上。2、当画笔样式被修改时,将数据保存到管理器中。3、和tuyaView通过UINavigationController跳转,各种控件通过Storyboard实现;

PropertyView.m

 @interface PropertyView ()

 @property (weak, nonatomic) IBOutlet UILabel *lalPen;
@property (weak, nonatomic) IBOutlet UISlider *slider; @property (nonatomic, strong)manager * m;
@property (weak, nonatomic) IBOutlet UISlider *sliderRed;
@property (weak, nonatomic) IBOutlet UISlider *sliderGreen;
@property (weak, nonatomic) IBOutlet UISlider *sliderBlue;
@property (weak, nonatomic) IBOutlet UISlider *sliderAlpha; @property (weak, nonatomic) IBOutlet UILabel *lalRed;
@property (weak, nonatomic) IBOutlet UILabel *lalGreen;
@property (weak, nonatomic) IBOutlet UILabel *lalBlue;
@property (weak, nonatomic) IBOutlet UILabel *lalAlpha; @property (weak, nonatomic) IBOutlet UIView *colorView; @end @implementation PropertyView -(void)viewDidLoad
{
[super viewDidLoad];
self.m = [manager shared];
self.slider.value = self.m.penValue;
self.lalPen.text = [NSString stringWithFormat:@"画笔宽度:%0.1lf",self.m.penValue]; self.lalRed.text = self.lalRed.text = [NSString stringWithFormat:@"红:%0.0f",self.m.red];
self.lalGreen.text = [NSString stringWithFormat:@"红:%0.0f",self.m.green];
self.lalBlue.text = [NSString stringWithFormat:@"红:%0.0f",self.m.blue];
self.lalAlpha.text = [NSString stringWithFormat:@"透明度:%0.0f", - self.m.penAlpha]; self.sliderRed.value = self.m.red;
self.sliderGreen.value = self.m.green;
self.sliderBlue.value = self.m.blue;
self.sliderAlpha.value = - self.m.penAlpha; self.colorView.backgroundColor = self.m.penColor;
} - (IBAction)PenSliderValueChanged:(UISlider *)sender
{
self.lalPen.text = [NSString stringWithFormat:@"画笔宽度:%0.1lf",sender.value];
self.m.penValue = sender.value;
} 当4slider改变时回调同一个方法;
- (IBAction)ColorChanged:(UISlider *)sender {
switch (sender.tag) {
case :
self.lalRed.text = [NSString stringWithFormat:@"红:%0.0f",sender.value];
self.m.red = sender.value;
break;
case :
self.lalGreen.text = [NSString stringWithFormat:@"绿:%0.0f",sender.value];
self.m.green = sender.value;
break;
case :
self.lalBlue.text = [NSString stringWithFormat:@"蓝:%0.0f",sender.value];
self.m.blue = sender.value;
break;
case :
self.lalAlpha.text = [NSString stringWithFormat:@"透明度:%0.1f",sender.value];
self.m.penAlpha = - sender.value;
break; default:
break;
}
self.colorView.backgroundColor = self.m.penColor;
} @end

数据管理器:储存画笔样式

manager.h

 @interface manager : NSObject

 @property (nonatomic, assign) CGFloat penValue;

 @property (nonatomic, assign) CGFloat red;
@property (nonatomic, assign) CGFloat green;
@property (nonatomic, assign) CGFloat blue;
@property (nonatomic, strong) UIColor * penColor;
@property (nonatomic, assign) CGFloat penAlpha; + (instancetype)shared; @end

manager.m

 + (instancetype)shared
{
static manager * m = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
m = [[manager alloc] init];
});
return m;
}
初始化颜色
-(UIColor *)penColor
{
_penColor = [UIColor colorWithRed:self.red / green:self.green/ blue:self.blue / alpha: - self.penAlpha];
return _penColor;
} 初始化画笔宽度
-(CGFloat)penValue
{
if (!_penValue) {
_penValue = 1.0;
}
return _penValue;
}

iOS_Quartz2D之涂鸦板的更多相关文章

  1. 重新想象 Windows 8 Store Apps (51) - 输入: 涂鸦板

    [源码下载] 重新想象 Windows 8 Store Apps (51) - 输入: 涂鸦板 作者:webabcd 介绍重新想象 Windows 8 Store Apps 之 涂鸦板 通过 Poin ...

  2. Android应用开发实例篇(1)-----简易涂鸦板

    链接地址:http://www.cnblogs.com/lknlfy/archive/2012/03/03/2378328.html 一.概述 这次要做一个简单的涂鸦板应用,以前在Qt上实现过,突然想 ...

  3. HTML5实现涂鸦板

    原文:HTML5实现涂鸦板 最近闲的,看了看html5,强大的绘图功能让我惊奇,于是,写了个小玩意---涂鸦板,能实现功能有:画画,改色,调整画笔大小 html5的绘图可以分为点,线,面,圆,图片等, ...

  4. 实现简单的手写涂鸦板(demo源码)

    在一些软件系统中,需要用到手写涂鸦的功能,然后可以将涂鸦的结果保存为图片,并可以将"真迹"通过网络发送给对方.这种手写涂鸦功能是如何实现的了?最直接的,我们可以使用Windows提 ...

  5. 背水一战 Windows 10 (60) - 控件(媒体类): Pointer 涂鸦板, InkCanvas 涂鸦板

    [源码下载] 背水一战 Windows 10 (60) - 控件(媒体类): Pointer 涂鸦板, InkCanvas 涂鸦板 作者:webabcd 介绍背水一战 Windows 10 之 控件( ...

  6. PPAPI+Skia实现的涂鸦板

    在PPAPI插件中使用Skia画图介绍了怎样在PPAPI中使用Skia,文末说回头要提供一个简单的涂鸦板插件,这次我来兑现承诺了. foruok原创,关注微信订阅号"程序视界"可联 ...

  7. mooc上学习acllib后写的包含背景音乐的小涂鸦板(初入江湖,大佬勿喷)

    #include "acllib.h"ACL_Sound sound1;ACL_Image img;//开始图ACL_Image img1;//涂鸦图ACL_Color c=RED ...

  8. 【Android】自己定义View、画家(画布)Canvas与画笔Paint的应用——绘图、涂鸦板app的实现

    利用一个简单的绘图app来说明安卓的图形处理类与自己定义View的应用. 例如以下图,有一个供用户自己随意绘图.涂鸦的app. 这里不做那么花俏了,仅提供黑白两色.但能够改变笔尖的粗细. 实质上这里的 ...

  9. qt练习10 涂鸦板源代码

    源代码下载: http://files.cnblogs.com/hnrainll/doodle.zip http://www.cnblogs.com/hnrainll/archive/2011/05/ ...

随机推荐

  1. VMware-workstation-full-12.0.0-2985596&VMware-player-12.0.0-2985596

    VMware-workstation-full-12.0.0-2985596 永久KEY:YV3D2-A0D50-481XP-KPNGE-ZV2ZF VMware-player-12.0.0-2985 ...

  2. 柏克EPS应急电源签约联达大厦保安全

    近日,柏克EPS应急电源成功签约佛山市联达大厦,保障大厦电力安全. 佛山市联达大厦占地6674㎡,总建筑面积约4.6万㎡,设有两层地下室,提供201个停车位,地面29层.大厦大楼分为主楼和副楼,主楼地 ...

  3. Kindle使用的一些方法

    最大的好处就是方便,买书便宜,到手我就买了六部书,十块钱不到,以纸书的价格一本都买不到,能够买一些一直想读一下,但又担心读不下去的书.而且买了之后完全不用担心书柜收纳不下了.另外很轻便,放在包里上下班 ...

  4. AFNetworking之缓存篇

    苦苦看了我两天,最近后台为了减轻压力,要我做缓存,我说好吧...... 借鉴了别人的说法找到一张图可以看明白好多:       这个是我比较战成一种方案. 好了直接上代码了 首先我们要有自己缓存的类 ...

  5. Bootstrap CSS概览代码文字标注篇

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  6. CIImage实现滤镜效果

    Core Image also provides autoadjustment methods that analyze an image for common deficiencies and re ...

  7. get方式提交中文乱码解决

    get方式提交中文时会乱码,过滤器只过滤post请求,此时可修改tomcat配置文件server.xml,为Connector添加属性URIEncoding="utf-8". ec ...

  8. 关于Python中的文件操作(转)

    总是记不住API.昨晚写的时候用到了这些,但是没记住,于是就索性整理一下吧: python中对文件.文件夹(文件操作函数)的操作需要涉及到os模块和shutil模块. 得到当前工作目录,即当前Pyth ...

  9. python简易爬虫来实现自动图片下载

    菜鸟新人刚刚入住博客园,先发个之前写的简易爬虫的实现吧,水平有限请轻喷. 估计利用python实现爬虫的程序网上已经有太多了,不过新人用来练手学习python确实是个不错的选择.本人借鉴网上的部分实现 ...

  10. foreach循环 Java

    第一次遇到foreach循环,是在PHP的数组中,同样,在Java数组中,也遇到了foreach循环,都是用来遍历数组(集合).遍历数组,首先想到的一般都是用while,do while,for循环, ...