CGContextRef 实现简易涂鸦板
写代码之前,先说一下涂鸦,涂鸦是指漫无目的地乱写乱画。今天我们不管乱写,因为乱写只需要一个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 实现简易涂鸦板相关推荐
- android 简易涂鸦板,canvas实现的简易涂鸦板效果
用canvas实现的简易涂鸦板效果,用鼠标点击在画布上随意涂鸦 涂鸦 *{ margin: 0; padding: 0; } #canvas1{ box-shadow: 0 5px 40px blac ...
- Canvas制作简易涂鸦板
使用canvas可以做到许多意想不到的功能,尤其动画方面,这次在vue项目中使用canvas制作一个简易涂鸦板 1. html部分代码 <template><div id=" ...
- HTML5实例教程——简易涂鸦板-何韬-专题视频课程
HTML5实例教程--简易涂鸦板-6858人已学习 课程介绍 用CANVES制作一个涂鸦板,让初学者初步了解HTML5的语言与功能. 课程收益 快速学会涂鸦板的做法,同时对HT ...
- UI进阶--Quartz2D和触摸事件的简单使用:简易涂鸦板
需求:实现一个简易的涂鸦板应用,使用鼠标在涂鸦板内拖动即可进行涂鸦,点击保存按钮,可以把完成的涂鸦保存,点击回退按钮可以向后退回一步,点击清空可以让涂鸦板清空. 实现步骤: 1.布局storyboar ...
- Android应用开发实例篇(1)-----简易涂鸦板
一.概述 这次要做一个简单的涂鸦板应用,以前在Qt上实现过,突然想到要把它在Android上实现,呵呵,既简单又有趣. 二.实现 新建工程MyWall,修改/res/layout/main.xml文件 ...
- HTML5简易涂鸦板制作
运行效果 代码中主要要学会阅读英文单词,务必认真学习English 代码清单1 <!DOCTYPE html> <html><head><meta chars ...
- ActionsScript 3.0简易涂鸦板
使用的编辑器是FlashDevelop(汉化版) 需要注意的是,该例子使用到了Button (属于flash cs3/cs4 中fl组件,位于fl.controls包下,而此编辑器默认不包含fl包) ...
- 【Qt】2D绘图之涂鸦板
00. 目录 文章目录 00. 目录 01. 概述 02. 开发环境 03. 程序设计(基本功能) 04. 程序设计(放大功能) 05. 程序设计(放大功能) 06. 附录 01. 概述 结合前面所学 ...
- [Qt教程] 第17篇 2D绘图(七)涂鸦板
[Qt教程] 第17篇 2D绘图(七)涂鸦板 楼主 发表于 2013-5-2 21:37:41 | 查看: 1255| 回复: 16 涂鸦板 版权声明 该文章原创于Qter开源社区(www.qter ...
最新文章
- 微信小程序架构分析 (上)
- 离开网易的转型之路1:选择测试之路-路上的迷茫
- UVa11389 The Bus Driver Problem(贪心)
- 计算机专业技能高考试题素材,计算机技能高考模拟试题
- linux刻录文件,Linux命令行下刻录CD-ROM数据光盘详细过程
- VC实现文件拖拽获取文件名
- Cadence Allegro元件更换层图文教程
- 卖零食怎么引流?怎么推广自己的零食产品,零食店怎么做引流?
- 福建省2020年计算机学业水平考试时间,2020学业水平考试时间表
- Java求100000以内素数_100000以内的质数表
- 小米手环如何连接苹果手机
- k8s nginx ingress 显示证书错误
- JS设计模式(二)-Revealing Module(揭示模式)
- 高压带电显示器局放检测面板式四合一局放在线监测/带电故障显示/无线测温装置
- 在代码里面如何使用workman
- 大型综合网络搭建详细步骤教程
- 小学计算机教师业务笔记,信息技术教师业务学习笔记
- 人工智能第四章第四丶五和六节知识总结
- 20 个好用的 Web API
- 音频文件如何转换成MP3格式?一分钟教你搞定