写代码之前,先说一下涂鸦,涂鸦是指漫无目的地乱写乱画。今天我们不管乱写,因为乱写只需要一个textview。下面说说如何实现乱画的功能。

说的是一个日本人想要切腹,那他得先找把刀,最次也要弄把改锥来,至于捅几下,捅进去之后切不切得动,那就要靠实践了。咱们用不着那么血腥,但是也需要先确定一下,咱们用什么来实现涂鸦。翻了翻API文档,决定用CGContext来实现我们这一目标。

首先我们要弄明白如何才能在UIView上画出一条线来,然后再思考如何能随心所欲地画出鼠标移动的轨迹,当然如果是真机进行调试,那就是手指移动的轨迹。

CGContext的API中有如下几个函数,可以初步实现我们绘制一条线段的想法:

// 设置线的颜色为白色

CGContextSetRGBStrokeColor(context,1.0,1.0,1.0,1.0);

// 保存当前的绘画状态,将这个状态推入栈(一个专门存储绘画状态的栈)内

CGContextSaveGState(context);

//接下来是设置线段

// 设置线段起点和终点

CGContextMoveToPoint(context,40.0,30.0);

CGContextAddLineToPoint(context,280.0,30.0);

// 设置线宽

CGContextSetLineWidth(context,self.width);

//设置端点的风格

CGContextSetLineCap(context,self.cap);

//描绘路径

CGContextStrokePath(context);

// 恢复之前的状态,并再次存储

CGContextRestoreGState(context);

在这里简单做一下解释,参数中的context是一个CGContextRef类型的数据,一般我们会将其设置为

UIGraphicsGetCurrentContext()的返回值;

CGContextSetRGBStrokeColor()函数用来设置线的颜色;

CGContextSaveGState()以及CGContextRestoreGState()两个函数需要成对出现

然后在二者中间添加对描绘内容的设置,比如

CGContextMoveToPoint()函数用来设置线的起点

CGContextAddLineToPoint()用来设置线的终点

CGContextSetLineWidth()用来设置线宽

CGContextSetLineCap()用来设置线段端点的样式等等等等

还有很多,有兴趣可以去API文档中扒拉扒拉。

以上就是实现画出一条线段的简单实现,那么我们要把它们写在哪里呢

很简单,只需要创建一个UIView的子类,然后定义一个实例方法,将这些代码写在这个实例方法中

最后在UIView的-drawRect:方法中去调用这个方法。下面详细说一下:

//1.创建一个UIView的子类DrawView,并在DrawView.h中声明一个方法:

- (void)drawLine:(CGContextRef)context;

然后在DrawView.m中将其实现,实现内容就写上述的那些函数。

//2.在-drawRect:方法中调用-drawLine:方法:

- (void)drawRect:(CGRect)rect {

[selfdrawInContext:UIGraphicsGetCurrentContext()];

}

在这里需要解释一下-drawRect:方法的触发

一般来说,我们会在一个视图控制器中去初始化我们创建的DrawView子类

如果初始化DrawView时设置了它的Rect,就会在视图控制的

-loadView和-viewDidLoad两个方法之后自动触发-drawRect:。

而在其他时刻,我们需要调用-setNeedsDisplay方法来触发-drawRect:。

下面来真正实现涂鸦,先看代码:

首先是定义UIView的子类ShowLineView。

在DrawLineView.h中写三个属性并声明两个方法:

#import <UIKit/UIKit.h>

@interface DrawLineView : UIView

//存放点的数组

@property (nonatomic,retain)NSMutableArray *totalArray;

//线宽

@property (nonatomic,assign,readwrite)CGFloat width;

//用来判断是否清空所绘内容

@property (nonatomic,assign)BOOL flag;

//绘制内容

- (void)drawInContext:(CGContextRef)context;

//通过pan手势将点存进数组

- (void)recordPointsWithPan:(UIPanGestureRecognizer *)pan;

@end

在DrawLineView.m中写如下内容:

#import "DrawLineView.h"

@implementation DrawLineView

-(void)dealloc

{

self.totalArray =nil;

[superdealloc];

}

- (void)drawInContext:(CGContextRef)context

{

//清空之前所绘内容

CGContextClearRect(context,self.bounds);

if (_flag) {

[selfclearPath:context];

_flag = NO;

} else {

for (NSMutableArray *array in _totalArray) {

for (int i = 1; i < array.count; i++) {

//设置画笔颜色

CGContextSetRGBStrokeColor(context,1.,1., 1.,1.);

//将当前状态推进栈内

CGContextSaveGState(context);

//设置起点

//CGPointValue是NSValue的实例方法,返回一个CGPoint

CGContextMoveToPoint(context, [array[i -1]CGPointValue].x, [array[i -1]CGPointValue].y);

//设置终点

CGContextAddLineToPoint(context, [array[i]CGPointValue].x, [array[i]CGPointValue].y);

//设置画笔宽度

CGContextSetLineWidth(context,_width);

//设置拐角风格

CGContextSetLineJoin(context,kCGLineJoinRound);

//显示所绘图形

CGContextStrokePath(context);

//将栈顶状态弹出,还原状态

CGContextRestoreGState(context);

}

}

}

}

- (void)recordPointsWithPan:(UIPanGestureRecognizer *)pan

{

//首先判断pan手势的状态,如果是开始状态,就创建一个可变数组,添加到属性totalArray中,如果不是就将pan手势所在的位置添加到totalArray的最后一个元素中

if (pan.state ==UIGestureRecognizerStateBegan) {

NSMutableArray *tempArray = [[NSMutableArrayalloc]initWithCapacity:0];

[_totalArrayaddObject:tempArray];

[tempArrayrelease];

[selfsetNeedsDisplay];

} else {

//-locationInView:方法可以获得手势所在的屏幕位置

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

//由于CGPoint类型的变量并不是对象,所以不能直接存到数组中,需要先转成NSValue类型,再存入数组

[[_totalArraylastObject]addObject:[NSValuevalueWithCGPoint:point]];

[selfsetNeedsDisplay];

}

}

//清空画面

- (void)clearPath:(CGContextRef)context

{

[_totalArrayremoveAllObjects];

CGContextClearRect(context,self.bounds);

[selfsetNeedsDisplay];

}

- (void)setWidth:(CGFloat)w

{

if (_width != w) {

_width = w;

}

[selfsetNeedsDisplay];

}

- (void)drawRect:(CGRect)rect {

[selfdrawInContext:UIGraphicsGetCurrentContext()];

}

@end

接下来是定义一个UIViewController的子类DrawLineViewController。

DrawLineViewController.h中不做修改,DrawLineViewController.m内容如下:

#import "DrawLineViewController.h"

#import "DrawLineView.h"

@interface DrawLineViewController ()

{

DrawLineView *lineView;

}

@end

@implementation DrawLineViewController

- (void)viewDidLoad {

[superviewDidLoad];

//创建一个拖拽手势

UIPanGestureRecognizer *pan = [[UIPanGestureRecognizeralloc]initWithTarget:selfaction:@selector(pan:)];

//初始化实例变量lineView

lineView = [[DrawLineViewalloc]initWithFrame:CGRectMake(0,20,320,400)];

lineView.totalArray = [NSMutableArrayarray];

lineView.userInteractionEnabled =YES;

[lineViewaddGestureRecognizer:pan];

[pan release];

[self.viewaddSubview:lineView];

[lineViewrelease];

//控制线宽的UISlider

UISlider *wSlider = [[UISlider alloc] initWithFrame:CGRectMake(60,450,260,30)];

wSlider.minimumValue =0.5;

wSlider.maximumValue =10;

[wSlider addTarget:selfaction:@selector(changeWidth:)forControlEvents:UIControlEventValueChanged];

[self.viewaddSubview:wSlider];

[wSlider release];

//清除按钮

UIButton *button = [UIButtonbuttonWithType:UIButtonTypeRoundedRect];

button.frame =CGRectMake(0,450,50,30);

button.layer.borderWidth =0.5;

[button setTitle:@"清除"forState:UIControlStateNormal];

[button addTarget:selfaction:@selector(clear)forControlEvents:UIControlEventTouchUpInside];

[self.viewaddSubview:button];

}

- (void)pan:(UIPanGestureRecognizer *)pan

{

[lineViewrecordPointsWithPan:pan];

}

- (void)changeWidth:(UISlider *)aSlider

{

lineView.width = aSlider.value;

}

- (void)clear

{

lineView.flag =YES;

[lineViewsetNeedsDisplay];

}

- (void)didReceiveMemoryWarning {

[superdidReceiveMemoryWarning];

// Dispose of any resources that can be recreated.

}

@end

整个程序就是这样了,这个小程序是用MRC写的,需要手动管理内存。仓促之下,并没有设想太多的功能,如果有兴趣,可以自行完善,比如实现改变线条颜色,撤销上一步操作等功能。今天就是这样,周末愉快。

CGContextRef 实现简易涂鸦板相关推荐

  1. android 简易涂鸦板,canvas实现的简易涂鸦板效果

    用canvas实现的简易涂鸦板效果,用鼠标点击在画布上随意涂鸦 涂鸦 *{ margin: 0; padding: 0; } #canvas1{ box-shadow: 0 5px 40px blac ...

  2. Canvas制作简易涂鸦板

    使用canvas可以做到许多意想不到的功能,尤其动画方面,这次在vue项目中使用canvas制作一个简易涂鸦板 1. html部分代码 <template><div id=" ...

  3. HTML5实例教程——简易涂鸦板-何韬-专题视频课程

    HTML5实例教程--简易涂鸦板-6858人已学习 课程介绍         用CANVES制作一个涂鸦板,让初学者初步了解HTML5的语言与功能. 课程收益     快速学会涂鸦板的做法,同时对HT ...

  4. UI进阶--Quartz2D和触摸事件的简单使用:简易涂鸦板

    需求:实现一个简易的涂鸦板应用,使用鼠标在涂鸦板内拖动即可进行涂鸦,点击保存按钮,可以把完成的涂鸦保存,点击回退按钮可以向后退回一步,点击清空可以让涂鸦板清空. 实现步骤: 1.布局storyboar ...

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

    一.概述 这次要做一个简单的涂鸦板应用,以前在Qt上实现过,突然想到要把它在Android上实现,呵呵,既简单又有趣. 二.实现 新建工程MyWall,修改/res/layout/main.xml文件 ...

  6. HTML5简易涂鸦板制作

    运行效果 代码中主要要学会阅读英文单词,务必认真学习English 代码清单1 <!DOCTYPE html> <html><head><meta chars ...

  7. ActionsScript 3.0简易涂鸦板

    使用的编辑器是FlashDevelop(汉化版) 需要注意的是,该例子使用到了Button (属于flash cs3/cs4 中fl组件,位于fl.controls包下,而此编辑器默认不包含fl包) ...

  8. 【Qt】2D绘图之涂鸦板

    00. 目录 文章目录 00. 目录 01. 概述 02. 开发环境 03. 程序设计(基本功能) 04. 程序设计(放大功能) 05. 程序设计(放大功能) 06. 附录 01. 概述 结合前面所学 ...

  9. [Qt教程] 第17篇 2D绘图(七)涂鸦板

    [Qt教程] 第17篇 2D绘图(七)涂鸦板 楼主  发表于 2013-5-2 21:37:41 | 查看: 1255| 回复: 16 涂鸦板 版权声明 该文章原创于Qter开源社区(www.qter ...

最新文章

  1. 微信小程序架构分析 (上)
  2. 离开网易的转型之路1:选择测试之路-路上的迷茫
  3. UVa11389 The Bus Driver Problem(贪心)
  4. 计算机专业技能高考试题素材,计算机技能高考模拟试题
  5. linux刻录文件,Linux命令行下刻录CD-ROM数据光盘详细过程
  6. VC实现文件拖拽获取文件名
  7. Cadence Allegro元件更换层图文教程
  8. 卖零食怎么引流?怎么推广自己的零食产品,零食店怎么做引流?
  9. 福建省2020年计算机学业水平考试时间,2020学业水平考试时间表
  10. Java求100000以内素数_100000以内的质数表
  11. 小米手环如何连接苹果手机
  12. k8s nginx ingress 显示证书错误
  13. JS设计模式(二)-Revealing Module(揭示模式)
  14. 高压带电显示器局放检测面板式四合一局放在线监测/带电故障显示/无线测温装置
  15. 在代码里面如何使用workman
  16. 大型综合网络搭建详细步骤教程
  17. 小学计算机教师业务笔记,信息技术教师业务学习笔记
  18. 人工智能第四章第四丶五和六节知识总结
  19. 20 个好用的 Web API
  20. 音频文件如何转换成MP3格式?一分钟教你搞定

热门文章

  1. 【光学】基于Matlab实现双缝干涉实验和牛顿环的实验
  2. 考研安排(各种经验贴总结)
  3. 天津渤海职业技术学院计算机宿舍,天津渤海职业技术学院宿舍条件,宿舍几人间环境好不好(图片)...
  4. 新型冠状病毒肺炎相关常用英语单词和词语
  5. 华隆机电直流屏电源模块维修HLM22010A-6
  6. 【golang】使用iota
  7. JSP自定义标签必知必会
  8. 写出常用的5个linux命令 并解释,Linux系统介绍(五)常用命令
  9. 笔记本必备驱动安装说明
  10. 从0到10000小时,从外包到字节跳动