iOS Quartz 2D绘图

无论使用哪种绘图技术,都离不开UIView,绘制都发生在UIView对象的区域内。如果是默认视图,绘制工作是由iOS系统自动处理的;如果是自定义视图,则必须重写drawRect:方法,在此提供相应的绘制代码。

1、drawRect:方法

想要绘图就要重写drawRect:方法。另外慧慧使用到setNeedsDisplay:setNeedsDisplayInRect:方法。
两个方法用于设置视图或者视图部分区域是否需要重新绘制。
setNeedsDisplay: 用于重新绘制这个视图。
setNeedsDisplayInRect:
用于重新绘制视图的部分区域。
原则上不要绘制整个视图,以减少绘制带来的开销。
触发视图重新绘制的动作有如下几种:
(1)当遮挡你的视图的其他视图被移动或删除时。
(2)将视图的hidden属性生命设置为false,使其从隐藏状态变为可见。
(3)将视图滚出屏幕,然后再重新回到屏幕上。
(4)显示调用视图的setNeedsDisplay:或者setNeedsDisplayInRect:方法。

例1:将整个屏幕所在的视图填充为蓝色。视图轮廓是一个矩形,我们只需要将视图所在的矩形填充即可。
swift代码

// An highlighted block
import UIKit
class view1:UIView{
	override func draw(_ rect:CGRect){
		UIColor.blue.setFill()
		/*
		用于为当前的图形上下文设置要填充的颜色。
		blue为UIColor的静态属性,获得蓝色对象
		setFill方法用于设置颜色要进行填充处理。
		*/
		UIRectFill(rect)//按照设置的颜色(blue蓝色)填充rect。
	}
}

objective-C代码

// An highlighted block
//view1.h文件
#import <UIKit/UIkit.h>
@interface view1:UIView
@end
//view1.m文件
#import "view1.h"
@implementation view1

-(void)drawRect:(CGRect)rect{
	[[UIColor blueColor] setFill];
	/*
		用于为当前的图形上下文设置要填充的颜色。
		blueColor为UIColor的静态属性,获得蓝色对象
		setFill方法用于设置颜色要进行填充处理。
		*/
	UIRectFill(rect);
}
2、填充与描边

UIKit提供了非常基本的绘图功能,主要的API如下:
(1)UIRectFill(CGRect rect),填充矩形函数
(2)UIRectFrame(CGRect rect),绘制矩形边框函数。
(3)UIBezierPath,绘制常见路径类,包括线段、弧线、矩形、圆角矩形和椭圆。
UIKit虽然提供了UIBezierPath等类,但是对线段、渐变、阴影、反锯齿等高级特性的支持不如Quartz 2D。

:UIRectFrame(CGRect rect)函数用法
swift代码

// An highlighted block
override func draw(_ rect:CGRect){
	UIColor.blue.setFill()
	UIRectFill(rect)
	/*
	下面两行,是在视图上绘制一个白色的矩形边框,绘制边框的过程称为描边(stroke)。
	*/
	UIColor.white.setStroke()//设置当前的图形上下文要描边的颜色为白色。
	let frame=CGrect(x:20,y:30,width:100,height:300)
	UIRectFrame(frame)//调用描边函数进行描边
}

objective-c代码

// An highlighted block
-(void)drawRect:(CGRect)rect{
	[[UIColor blueColor] setFill];
	UIRectFill(rect);
	/*
	下面两行,是在视图上绘制一个白色的矩形边框,绘制边框的过程称为描边(stroke)。
	*/
	[[UIColor whiteColor] setStroke];//设置当前的图形上下文要描边的颜色为白色。
	CGRect frame=CGRectMake(20,30,100,300);
	UIRectFrame(frame);//调用描边函数进行描边
}
3、绘制图像和文本

绘制图像和文本的效果就像是使用标准控件(UILabel和UIImage)一样。这些绘制可以使用UIImage和NSString实现,方法如下:
UIIMage类:
(1)drawAtPoint:,在指定的绘制点绘制图片,如果图片宽度超过屏幕宽度,则图片的部分内容无法显示。
(2)drawInRect:,在指定的矩形例绘制图片。
(3)drawAsPatternInRect:,在指定矩形例平铺绘制图片,如果图片大小超出了指定的矩形,形式上与drawAtPoint:方法类似,如果图片大小小于指定的矩形,就会有平铺效果。
NSString类:
(1)drawAtPoint:withAttributes:,文本在指定点绘制。
(2)drawInRect:withAttributes:,文本在指定的矩形例绘制。

例1
swift代码

// An highlighted block
override func draw(_ rect:CGRect){
//填充白色背景
UIColor.white.setFill()
UIRectFill(rect)

let image=UIImage(named:"cat")
//设置一个rect矩形区域
let imageRect=CGRect(x:0,y:0,width:UIScren.main.bounds.size.width,height:UIScren.main.bounds.size.width)
//绘制图片
image!.draw(in:imageRect)
//image!.drow(at:CGPoint(x:0,y:40))
//image!.drowAsPattern(in:CGRect(x:0,y:0,width:320,height:400))


let title:NSString ="猫猫猫猫"
let font =UIFont.systemFont(ofSize:14)//创建字号14的系统字体。
let attr=[NSFontAttributeName:font]//将UIFont对象放到attr字典集合中
//获得字符串大小
let size=title.size(attributes:attr)
//水平居中时X轴坐标
let xpos=UIScreen.main.bounds.midX-size.width/2//获取水平居中时的X坐标
//绘制字符串
title.draw(at:CGPoint(x:xpos,y:20),widthAttributes:attr)
//let stringRect=CGRect(x:xpos,y:60,width:100,height:40)
//title.draw(in:stringRect,withAttributes:attr)
}

objective-C代码

// An highlighted block
-(void)drawRect:(CGRect)rect{
	//填充白色背景
	[[UIColor whiteColor] setFill];
	UIRectFill(rect);
UIImage* image=[UIImage imageNamed:@"cat"];

//设置一个rect矩形区域
CGRect imageRect=CGRectMake(0,40,[[UIScreen mainScreen] bounds].size.width,[[UIScreen mainScreen] bounds].size.width);
//绘制图片
[image drawInRect:imageRect];
//[image drawAtPoint:CGPointMake(0,40)];
//[image drawAsPatternInRect:CGRectMake(0,0,320,400)];


NSString *title=@"猫猫猫猫";
UIFont *font=[UIFont systemFontOfSize:14];//创建字号14的系统字体。
NSDictionary *attr=@{NSFontAttributeName:font};//将UIFont对象放到attr字典集合中
//获得字符串大小
CGSize size=[title sizeWithAttributes:attr];
//水平居中时X轴坐标
CGFloat xpos=[[UIScreen mainScreen] bounds].size.width/2-size.width/2;
//绘制字符串
[title drawAtPoint:CGPointMake(xpos,20) withAttributes:attr];
//CGRect stringRect=CGRectMake(xpos,60,100,40);
//[title drawInRect:stringRect withAttributes:attr];
}
4、Quartz图形上下文

图形上下文包含绘制系统执行后绘制命令所需要的信息,它定义了各种基本的绘制参数,如绘制使用的颜色、剪裁区域、线段的宽度及风格信息、字体信息等。这些信息被封装到CGContext对象中,CGContext就是图形上下文。我们可以自定义图形上下文,这可以通过UIGraphicsGetCurrentContext函数实现。


在视图中绘制一个蓝色三角形,可以分几个步骤。
(1)通过路径描述三角形轮廓。
(2)三角形轮廓描边。
(3)三角形填充红色。
(4)绘制路径。
swift代码

// An highlighted block
override func draw(_ rect:CGRect){
	//填充白色背景
	UIColor.white.setFill()
	UIRectFill(rect)

	//自定义图形上下文
	let context=UIGraphicsGetCurrentContext()//创建图形上下文对象
	context!.move(to: CGPoint(x:75,y:10))//表示以(75,10)作为绘制起始点
	context!.addLine(to: CGPoint(x:10,y:150))//表示绘制从(75,10)到(10,150)的线段
	context!.addLine(to: CGPoint(x:160,y:150))
	context!.closePath()//闭合路径

	//设置黑色描边参数
	UIColor.black.setStroke()
	//设置蓝色填充参数
	UIColor.blue.setFill()
	//绘制路径
	context!.drawPath(using: CGPathDrawingMode.fillStroke)//实现绘制路径,其中kCGPathFillStroke是填充描边处理,它是CGPathDrawingMode枚举类型中定义的成员,其中常用的成员有kCGPathFill和kCGPathStroke,分别代表填充和描边处理,fillStroke是填充描边处理
}

objective-C代码

// An highlighted block
-(void)drawRect:(CGRect)rect{
	//填充白色背景
	[[UIColor whiteColor] setFill];
	UIRectFill(rect);

	//自定义图形上下文
	CGContextRef context=UIGraphicsGetCurrentContext();//创建图形上下文对象
	CGContextMoveToPoint(context,75,10);
	CGContextAddLineToPoint(context,10,150);
	CGContextAddLineToPoint(context,160,150);
	CGContextClosePath(context);

	//设置黑色描边参数
	[[UIColor blackColor] setStroke];
	//设置蓝色填充参数
	[[UIColor blueColor] setFill];
	//绘制路径
	CGContextDrawPath(context,kCGPathFillStroke);
}

运行结果
在这里插入图片描述

5、Quartz路径

路径可以用来描述矩形、圆形及其他2D几何图形。通过路径,我们可以对几何图形进行描边、填充和米欧彼岸填充处理。Core Graphics(Quartz 2D)中有4个基本图元用于描述路径:点、线段、弧和贝塞尔(Bezier)曲线。
(1)点
点是二位控件中的一个位置,不用把它当成像素,一个点完全不占控件,所以画一个点不会在屏幕上显示任何东西。
(2)线段
线段由两个点定义:起点和终点。线段可以通过描边绘制出来,我们可以通过设置图形上下文,如画笔宽度或者颜色等参数,绘制出两点之间的线段。线段没有面积,所以他们不能被填充。我们可以用一组线段或曲线组成一个具有闭合路径的集合图形,然后填充它。
(3)弧
弧可以由一个圆心点、半径、起始角和结束角描述。圆和弧的特例,指需要设置起始角为0度,结束角为360度就可以了。因为弧是占有一定面积的路径,所以可以被填充、描边和描边填充出来。
(4)贝塞尔曲线
任何一条曲线都可以通过与它相切的控制线两端的点的位置来定义。因此,贝塞尔曲线可以用4个点描述,其中两个描述两个端点,另外两个点描述每一个端的切线。贝塞尔曲线可以分为:二次方贝塞尔曲线高阶贝塞尔曲线

:贝塞尔曲线
swift代码

// An highlighted block
override func draw(_ rect:CGRect){
	//填充白色背景
	UIColor.white.setFill()
	UIRectFill(rect)

	let context=UIGraphicsGetCurrentContext()
        context!.move(to:CGPoint(x:333, y:0))
        context!.addCurve(to:CGPoint(x:330,y:36),control1:CGPoint(x:333,y:0),control2:CGPoint(x:332,y:26))
        //添加贝塞尔曲线
        context!.addCurve(to:CGPoint(x:299,y:26),control1:CGPoint(x:330,y:26),control2:CGPoint(x:299,y:20))
        context!.addLine(to:CGPoint(x:296,y:17))
        context!.addCurve(to:CGPoint(x:291,y:19),control1:CGPoint(x:296,y:17),control2:CGPoint(x:196,y:19))
        context!.addLine(to:CGPoint(x:250,y:19))
        context!.addCurve(to:CGPoint(x:238,y:19),control1:CGPoint(x:250,y:19),control2:CGPoint(x:227,y:24))
        context!.addCurve(to:CGPoint(x:227,y:24),control1:CGPoint(x:236,y:20),control2:CGPoint(x:234,y:24))
        context!.addCurve(to:CGPoint(x:216,y:19),control1:CGPoint(x:220,y:24),control2:CGPoint(x:217,y:19))
        context!.addCurve(to:CGPoint(x:207,y:20),control1:CGPoint(x:214,y:20),control2:CGPoint(x:211,y:22))
        context!.addCurve(to:CGPoint(x:182,y:21),control1:CGPoint(x:207,y:20),control2:CGPoint(x:187,y:20))
        context!.addLine(to:CGPoint(x:100,y:45))
        context!.addLine(to:CGPoint(x:97,y:46))
        context!.addCurve(to:CGPoint(x:64,y:72),control1:CGPoint(x:97,y:46),control2:CGPoint(x:86,y:71))
        context!.addCurve(to:CGPoint(x:23,y:48),control1:CGPoint(x:42,y:74),control2:CGPoint(x:26,y:56))
        context!.addLine(to:CGPoint(x:9,y:47))
        context!.addCurve(to:CGPoint(x:0,y:0),control1:CGPoint(x:9,y:74),control2:CGPoint(x:0,y:31))
        context!.strokePath()
}
6、Quartz坐标变换

图形的另外一种操作便是变换,主要包括平移、缩放、旋转灯变换,变换离不开坐标,不同的绘图系统对于坐标系统的定义也有区别。
Quartz 2D,坐标原点在左下角。
UIKit,坐标原点在左上角

CTM变换
**(1)CGContextRotateCTM:**旋转变换
**(2)CGContextScaleCTM:**缩放变换
**(3)CGContextTranslateCTM:**平移变换


swift代码

// An highlighted block
override func draw(_ rect:CGRect)
{
	//填充白色背景
	UIColor.white.setFill()
	UIRectFill(rect)

	//创建UIImage图片对象
	let uiImage=UIImage(named:"cat")
	//将UIImage图片对象转换为CGImage图片对象
	let cgImage=uiImage!.cgImage

	let context=UIGraphicsGetCurrentContext()

	//平移变换
	context!.translateBy(x:100,y:50)
	let imageRect=CGRect(x:0,y:0,width:uiImage!.size.width,height:uiImage!.size.height)
	context!.draw(cgImage!,in:imageRect)

/*
	//缩放变换
	context!.scaleBy(x:0.5,y:0.75)
	let imageRect=CGRect(x:0,y:0,width:uiImage!.size.width,height:uiImage!.size.height)
	context!.draw(cgImage!,in:imageRect)


	//旋转变换
	context!.rotate(by:CGFloat(45.0*M_PI/180.0))
	let imageRect=CGRect(x:0,y:0,width:uiImage!.size.width,height:uiImage!.size.height)
	context!.draw(cgImage!,in:imageRect)
	*/
}

objective-C代码

// An highlighted block
-(void)drawRect:(CGRect)rect{
	[[UIColor whiteColor] setFill];
	UIRectFill(rect);

	//创建UIImage图片对象
	UIImage *uiImage=[UIImage imageNamed:@"cat"];
	//将UIImage图片对象转换为CGImage图片对象
	CGImageRef cgImage=uiImage.CGImage;

	CGContextRef context=UIGraphicsGetCurrentContext();

	//平移变换
	CGContextTranslateCTM(context,100,50);
	CGRect imageRect=CGRectMake(0,0,uiImage.size.width,uiImage.size.height);
	cGContextDrawImage(context,imageRect,cgImage);

	/*
	//缩放变换
	CGContextScaleCTM(context,0.5,0.75);
	CGRect imageRect=CGRectMake(0,0,uiImage.size.width,uiImage.size.height);
	cGContextDrawImage(context,imageRect,cgImage);

	//旋转变换
	CGContextRotateCTM(contet,(45.0*M_PI/180.0));
	CGRect imageRect=CGRectMake(0,0,uiImage.size.width,uiImage.size.height);
	cGContextDrawImage(context,imageRect,cgImage);
	*/
}

组合变换
有些情况下,我们需要组合变换,从而得到累加效果。默认情况下,采用Quartz绘制的图片都是倒置的。要想绘制出正常效果的图片,则需要进行一列的组合变化。

swift代码

// An highlighted block
override func draw(_ rect:CGRect)
{
	//填充白色背景
	UIColor.white.setFill()
	UIRectFill(rect)

	//创建UIImage图片对象
	let uiImage=UIImage(named:"cat")
	//将UIImage图片对象转换为CGImage图片对象
	let cgImage=uiImage!.cgImage

	let context=UIGraphicsGetCurrentContext()

	//平移变换
	context!.translateBy(x:100,y:50)
	//缩放变换
	context!.scaleBy(x:0.5,y:0.75)
	//旋转变换
	context!.rotate(by:CGFloat(45.0*M_PI/180.0))
	let imageRect=CGRect(x:0,y:0,width:uiImage!.size.width,height:uiImage!.size.height)
	context!.draw(cgImage!,in:imageRect)
}

objective-C代码

// An highlighted block
-(void)drawRect:(CGRect)rect{
	[[UIColor whiteColor] setFill];
	UIRectFill(rect);

	//创建UIImage图片对象
	UIImage *uiImage=[UIImage imageNamed:@"cat"];
	//将UIImage图片对象转换为CGImage图片对象
	CGImageRef cgImage=uiImage.CGImage;

	CGContextRef context=UIGraphicsGetCurrentContext();

	//平移变换
	CGContextTranslateCTM(context,100,50);
	//缩放变换
	CGContextScaleCTM(context,0.5,0.75);
	//旋转变换
	CGContextRotateCTM(contet,(45.0*M_PI/180.0));
	CGRect imageRect=CGRectMake(0,0,uiImage.size.width,uiImage.size.height);
	cGContextDrawImage(context,imageRect,cgImage);
}

仿射变换
它可以将多次变换的效果累加起来,但当前变换举着却不能。例如,先平移(100,200)再旋转30度,它会将这两次变化效果累加起来,当前变换矩阵指旋转30度,不会济宁平移(100,200)。因此,仿射变换可以重用变换,每次变换都可以用矩阵表示,通过多次矩阵相乘得到最后的结果。仿射变换是CGAffineTransform结构体的类型,所有的放射函数的返回值都是CGAffineTransform实例,如下:
**(1)CGAffineTransformMakeRotation:**创建并初始化旋转矩阵,对应的Swift版本是init(rotationAngle:CGFloat)
**(2)CGAffineTransformMakeScale:**创建新的缩放矩阵,对应的Swift版本是init(saleX:CGFloat,y:CGFloat)。
**(3)CGAffineTransformMakeTranslation:**创建新的平移矩阵,对应的Swift版本是init(translationX:CGFloat,y:CGFloat)。
**(4)CGAffineTransformRotate:**旋转矩阵,对应的Swift版本是CGAffineTransform的rotated(by:CGFloat)方法。
**(5)CGAffineTransformScale:**缩放矩阵,对应的Swift版本是CGAffineTransform的scaledBy(x:CGFloat,y:CGFloat)方法
**(6)CGAffineTransformTranslate:**平移矩阵,对应Swift版本是CGAffineTransform的translatedBy(x:CGFloat,y:CGFloat)方法。

swift代码

// An highlighted block
override func draw(_ rect:CGRect)
{
	//填充白色背景
	UIColor.white.setFill()
	UIRectFill(rect)

	//创建UIImage图片对象
	let uiImage=UIImage(named:"cat")
	//将UIImage图片对象转换为CGImage图片对象
	let cgImage=uiImage!.cgImage

	let context=UIGraphicsGetCurrentContext()
	
	//缩放变换
	var myAffine=CGAffineTransform(scaleX:1,y:-1)
	//平移变换
	myAffine=myAffine.translatedBy(x:0,y:-uiImage!.size.height)
	//连接到CTM矩阵
	context!.concatenate(myAffine)

	let imageRect=CGRect(x:0,y:0,width:uiImage!.size.width,height:uiImage!.size.height)
	context!.draw(cgImage!,in:imageRect)
}

objective-C代码

// An highlighted block
-(void)drawRect:(CGRect)rect{
	[[UIColor whiteColor] setFill];
	UIRectFill(rect);

	//创建UIImage图片对象
	UIImage *uiImage=[UIImage imageNamed:@"cat"];
	//将UIImage图片对象转换为CGImage图片对象
	CGImageRef cgImage=uiImage.CGImage;

	CGContextRef context=UIGraphicsGetCurrentContext();
	//缩放变换
	CGAffineTransform myAffine=CGAffineTransformMakeScale(1,-1);
	//平移变换
	myAffine=CGAffineTransformTranslate(myAffine,0,-uiImage.size.height);
	//连接CTM矩阵
	CGContextConcatCTM(context,myAffine);

	CGRect imageRect=CGRectMake(0,0,uiImage.size.width,uiImage.size.height);
	cGContextDrawImage(context,imageRect,cgImage);
}

参考资料
《IOS开发指南 从HELLO WORLD到APP STORE上架 第5版》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值