理论基础:
Core Graphics(核心图层)框架是一组基于C的API,可以用于一切绘图操作!
Quartz2D API 是Core Graphics框架的一部分因此在Quartz2D中很多的数据类型和方法都是以CG开头的
Quartz2D是一个二维图形绘制引擎,主要用来绘制二维图形,可以实现很多功能如:基于路径的绘图、透明度、阴影、颜色、管理、反锯齿、PDF文档的生成和PDF元数据访问等
Quartz2D与分辨率和设备无关意味着代码不管是在打印机还是其他设备都可以直接运行
在Xcode新建好项目,运用时不必引入Quartz2D框架的头文件这是因为:
项目中已经包含了#import <UIKit/UIKit.h>这个文件,而UIKit依赖于Core Graphics,那么Core Graphics框架会被自动引入,即UIKit内部已经包含了Core Graphics框架的主头文件,为了让开发者不必接触底层的Core Graphics的C接口UIKit内部已经封装了Core Graphics的一些API,但是有时候也可以直接利用Core Graphics的C接口。
所以当使用UIKit创建按钮、标签或者其他UIView的子类时,UIKit会用Core Graphics将这些元素绘制在屏幕上。此外UIEvent(UIKit中的事件处理类)也会使用Core Graphics用来帮助确定触摸事件在屏幕上所处的位置
理论中几个比较重要的概念:
1、图形:以路径的方式描述的一个形状。就是个形状比如圆、长方形等几何图形或者非几何图形只不过这里成为路径
2、图像:简单的说就是很多的像素点逐一绘制在屏幕上所呈现的路径
可以发现:图形和图像很类似,那么做个简单的对比吧
图形:是通过代码绘制路径的方式实现,因此可以是任何图形包括复杂图形。而且在绘制简单图形时效率高于图像。现在主要研究的就是图形的绘制
图像:可借助如PS、Adobe等三方工具,可以预先绘制并以文件形式保存。官方建议PNG格式的图像
绘图思路:
在哪里绘图?给视图中绘图,在图形上下文 Graphics Context 因此新建的项目没有View
只有控制器和StroyBoard前者是用来控制页面上视图显示的而后者没有绑定任何View呢
那么首先应该是在UIView中,然后在UIView的上下文中就可绘图
因此在ios中如果想在屏幕上绘图,需要创建一个UIView对象,并实现它的drawRect:方法,此方法在UIView显示在屏幕上及UIView内部的内容需要更新时调用,而且一个UIView需要被刷新或者重绘也会被调用(重绘时应该调用setNeedsDisplay而不能直接调用drawRect:方法,因为setNeedsDisplay会自动调用drawRect:方法)
执行方法后UIView对象自动配置绘图环境然后执行绘图操作
在配置的时候UIView对象会对绘图环境创建一个Graphics Context.通过调用UIGraphicsGetCurrentContext()方法获取当前的Graphics Context
Graphics Context是一个数据类型(CGContextRef),封装了Quartz绘图制图到输出设备的信息
Quartz2D中所有的对象都是绘制到一个Graphics Context中,不同的设备有不同的Graphics Context,一个Graphics Context表示一个绘制目标,它包含绘制系统用于完成绘制指令的绘制参数和设备相关信息
如何绘图——-
要绘图首先要理解几个概念:
1、Quartz2D 坐标系
默认的坐标(0,0)是左下角在ios中,运用UIGraphicsGetCurrentContext方法返回的图形将上下文的坐标原点修改到左上角(即沿着Y值从上到下增大,X值从左到右增大)
有时候需要修改坐标系来达到某些效果,比如屏幕的旋转。因此屏幕的旋转只不过是对上下文中的坐标系的操作而已。
操作坐标系的方法有:
(1)CGContextRotateCTM(CGContextRef c,CGFloat angle) 方法可以相对原点旋转上下文坐标系
(2)CGContextTranslateCTM(CGContextRef c,CGFloat x,CGFloat y) 方法可以相对原点平移上下文坐标系
(3)CGContexScaleCTM(CGContextRef c,CGFloat x,CGFloat y) 方法可以缩放上下文坐标系
注意:
转换坐标系前,使用CGContextSaveGState(CGContextRef c) 保存当前上下文状态
转换坐标系后,使用CGContextRestoreGSate(CGContextRef c) 恢复之前保存的上下文状态
2、绘图顺序
3、UIView的drawRect:方法
是在UIViewController的loadView和viewDidLoad两个方法之后调用的
如果UIView初始化时没有设置CGRectdrawRect:方法不会被调用
如果设置UIView的contentModel属性值为UIViewContentModeRedraw那么将在每次更改frame时自动调用drawRect:方法
如果使用UIView绘图,那么只能在drawRect:方法中获取相应的CGContextRef并绘图,而在其他方法中获取的CGContextRef不能用于绘图
4、Quartz2D 的内存管理
使用含有“Create“或者”Copy“的函数创建的对象,使用完毕后必须释放否则导致内存泄漏,反之则不用释放
如果retain了一个对象,不再使用需要将其release掉。可以使用Quartz2D的函数来指定retain和release一个对象。例如,如果创建了一个CGColorSpace对象则使用CGColorSpaceRetain和CGColorSpaceRelease来retain和release对象。也可以使用Core Foundation的CFRetain和CFRelease. 一定不能传递NULL值给这些函数
Quartz 2D绘图的基本步骤:
1、获取与视图相关的上下文对象
- UIGraphicsGetCurrentContext
2、创建及设置路径(path)
(1)创建路径
(2)设置路径起点
(3)增加路径内容
3、将路径添加到上下文
4、设置上下文属性
- 比如:边线颜色、填充颜色、线宽。。。
5、绘制路径
6、释放路径
最基本的绘图:
绘制直线以及其他常见的几何图形
建立项目:
1218绘制简单的几何图形
新建好项目后,因为没有视图所以新建一个YLMyView.h,然后在StoryBorad中指定一下,那么当程序启动的时候通过加载StoryBoard就可以加载新建的View了。新建的好的View中会自动生成代码:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
returnself;
}
但是这个方法将不会被执行,项目中所有的控制器或者View一旦通过StoryBoard或XIB加载后,它们的init方法都不被执行
//
// YLMyView.m
// 1218绘制简单的几何图形
//
// Created by apple on 13-12-21.
// Copyright (c) 2013年 All rights reserved.
//
#import "YLMyView.h"
@implementation YLMyView
/*
下面的代码是使用Quartz 2D框架绘图,而Quartz 2D是一套C语言的框架
那么先了解下C语言的使用方法:
1>在C语言中所有的对象,都是通过对象的引用地址来使用的,因此不需要使用*
NSString *str = @"hello word";
在引用的时候会这么写:
if(str == nil){
这里的str是指针(习惯用语)实际是内存地址内存地址是用一串
准确的说是无符号的长整型
nil 代表空 准确的说是0
从C语言的角度判断:非0即针
而代码中如:CGContextRef context = UIGraphicsGetCurrentContext();
是直接通过对象的引用地址来访问的
通过一段代码来表示:
NSString *str = @"Hello Word";
CGContextRef context = UIGraphGetCurrentContext();
这俩行代码执行后,通过断点显示:
str = (_NSCFConstantString *)@"Hello Word"
context = (CGContextRef)0x8a5ec40
可以看出:
context直接打印的是一个十六进制的数那意味着c语言中的对象是直接通过引用对象内存地址来使用的
str打印的。。。。那么oc中的对象是通过什么来使用的呢?*号代表访问内存。。。指针。。。
2>C语言是面向过程的语言,因此要引用某一个对象是通过函数来实现的
比如:CGContextRef context = UIGraphicsGetCurrentContext();在右边想获取context对象就是通过UIGraphicsGetCurrentContext()方法来实现的
3> ARC是OC的自动引用技术,如果是在C语言中,为对象分配了(create,copy)了内存,我们要自己释放对象的内存(释放可以使用Release方法)
CGMutablePathRef path = CGPathCreateMutable();
右边代码引用的是C语言中的函数,因此必须释放内存。这里涉及到了ARC和非ARC对象释放内存的问题!需要整理笔记!
4> 从代码中可以看出绘图使用了很多Core Graphics(核心图层)里面的类,因此很多都是以CG开头的,比如上下文CGContext-- 路径CGPath--
5> 设置线条颜色
设置RGB颜色后面四个参数分别是:红绿蓝透明度
red 美工数值为 0~255程序员值为 0~FF(将0~255转为16进制)比如:#00FF
green 美工数值为 0~255程序员值为 0~FF(将0~255转为16进制)比如:#00FF
blue 美工数值为 0~255程序员值为 0~FF(将0~255转为16进制)比如:#00FF
在OC中设置RGB颜色:
red --> r(0~255)/255 值为 0~1
green --> g(0~255)/255 值为 0~1
blue --> b(0~255)/255 值为 0~1
alpha 值为 0~1.0 0表示完全透明 1表示完全不透明在Quartz 2D 绘图的时候默认为1如果改变值的话会严重影响性能
*/
/*
所有的绘制代码在这里调用系统自动生成
*/
- (void)drawRect:(CGRect)rect
{
// NSString *str = @"hello word";
// CGContextRef context = UIGraphicsGetCurrentContext();
[selfdrawLine];
}
#pragma mark 绘制条直线
- (void)drawLine
{
// 1获取当前视图中的上下文 执行右边代码将原点修改到左上角(0,0)
CGContextRef context =UIGraphicsGetCurrentContext();
// 2 设置路径 含有create 使用完毕必须释放
CGMutablePathRef path =CGPathCreateMutable();
// 2.1 将原点移动到坐标(100,100) NUll表示不使用形变
CGPathMoveToPoint(path,NULL,100, 100);
// 2.2 增加一条直线 可以理解是将坐标(100,100)的点移动到坐标(200,200)
CGPathAddLineToPoint(path,NULL,200,200);
// 3 将路径添加到上下文
CGContextAddPath(context, path);
// 4设置上下文的属性设置线条颜色为红色
CGContextSetRGBStrokeColor(context,1.0,0,0,1);
/* 5将上下文中的路径绘制出来 即将点移动的轨迹绘制出来
// 方法中的第二个参数是填充模式定义了很多种填充方式(值以K开头)
enum CGPathDrawingMode {
kCGPathFill, // 填充绘制针对关闭的路径使用 中间重合部分也填充
kCGPathEOFill, // 抑或填充针对关闭的路径使用 中间重合部分不填充
kCGPathStroke, // 绘制线条无所谓路径是否关闭
kCGPathFillStroke, // 填充并绘制线条
kCGPathEOFillStroke // 抑或填充并画线
};
*/
CGContextDrawPath(context,kCGPathStroke);
// 6释放路径这句代码涉及到内存管理:在C语言中含有creat或者copy函数所创建的对象,是哟哦那个完毕后必须释放否则内存泄漏
CGPathRelease(path);
}
@end