Quartz 2D Programming Guide笔记
###Graphics Contexts图形上下文###
图形上下文(graphics context)是绘制目标,可以理解为画布,包含着绘图时的参数和设备信息。类型为CGContextRef。获取graphics context后,调用Quartz 2D的函数进行绘制、旋转等操作,还可以修改如线宽、填充颜色等绘画参数。
###获取图形上下文###
当view出现在屏幕上以及视图将要更新时,系统会调用view的drawRect:方法。我们创建UIView子类,并重写drawRect:方法,此时调用UIKit提供的方法UIGraphicsGetCurrentContext,来获取系统为我们准备好的当前绘图环境的graphics context对象,。
###路径###
路径构成一个或多个图形或子路径。子路径可以由直线、曲线或两者相结合组成。如图:
###点###
调用CGContextMoveToPoint,传入表示x和y坐标的两个float值来确定路径的起始点。
CGContextMoveToPoint(context, 50, 50);
###线段###
两个点确定一条线,线的起点为当前点,所以只需要确定终点。
1、调用CGContextAddLineToPoint,传入终点坐标来添加一条线。
CGContextAddLineToPoint(context, 100, 50);
2、调用CGContextAddLines可以添加多条线,传入点的数组,Quartz以第一个点为起点,然后用直线依次连接剩下的点。
GPoint aPoints[3];//坐标点
aPoints[0] = CGPointMake(100, 80);//坐标1
aPoints[1] = CGPointMake(130, 150);//坐标2
aPoints[2] = CGPointMake(130, 200);//坐标3
CGContextAddLines(context, aPoints, 3);
【实例1】
Quartz 2D简单绘制分割线:https://www.jianshu.com/p/52700532f854
###弧###
弧是圆的一部分,Quartz提供两个方法来创建弧。
1、CGContextAddArc,传入圆的中心点坐标(x,y)、半径、起始角度、结束角度、方向(1为时钟方向)。
CGContextAddArc(context, 100, 100, 50, M_PI_2 , 0, 1);
2、CGContextAddArcToPoint,传入两个终点的坐标值以及半径长度,Quartz以两个终点确定两条切线,从而确定弧。
【实例2】
可拖动的环形进度:http://blog.csdn.net/dolacmeng/article/details/46617517
###曲线###
二次和三次贝塞尔曲线可以确定各种各样的曲线形状,如图:
1、调用CGContextAddCurveToPoint函数,传入两个控制点、结束点,来确定一条三次贝塞尔曲线。
2、通过调用CGContextAddQuadCurveToPoint,传入控制点和结束点,确定一条二次贝塞尔曲线
【实例】贝塞尔曲线动画demo(仿美人相机效果):http://blog.csdn.net/dolacmeng/article/details/79276039
**实例中使用CAShapeLayer与UIBezierPath结合绘制,而非通过重写drawRect。UIBezierPath类可以创建基于矢量的路径,这个类在UIKit中,是Core Graphics框架关于path的一个封装。
CAShapeLayer和drawRect的比较:
- 1.drawRect:属于CoreGraphics框架,占用CPU,性能消耗大。
- 2.CAShapeLayer:属于CoreAnimation框架,通过GPU来渲染图形,节省性能。动画渲染直接提交给手机GPU,不消耗内存。
参考链接:https://www.jianshu.com/p/b1c38a3a67a9
###闭合路径###
调用CGContextClosePath,会添加一条从当前点到起始点的线来闭合当前的形状。
###椭圆###
椭圆是一个被压扁的圆形,调用CGContextAddEllipseInRect方法,传入一个用以确定椭圆边界的矩形。
CGContextAddEllipseInRect(context, CGRectMake(0, 0, 200, 100));
###矩形###
调用CGContextAddRect来添加一个矩形,传入一个包含原点坐标、宽度和高度的CGRect结构体。
CGContextAddRect(context, CGRectMake(0, 0, 200, 100));
可以一次添加多个矩形,只需调用CGContextAddRects方法,并传入CGRect结构体数组。
CGRect rects[4];
rects[0] = (CGRect){{0,0}, {50, 50}};
rects[1] = (CGRect){{100, 100}, {30, 30}};
rects[2] = (CGRect){{0,100}, {20, 20}};
rects[3] = (CGRect){{100,0}, {10, 10}};CGContextAddRects(context, rects, 4);
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGContextFillPath(context);
###Creating a Path###
创建路径:
在图形上下文中创建路径,先调用CGContextBeginPath.然后通过调用CGContextMoveToPoint设置起点。之后就绘制添加线、弧或曲线。总之记住:
- 在开始新路径前,调用CGContextBeginPath.
- 线、弧、曲线从当前点开始绘制,所以必须调用CGContextMoveToPoint来设置当前起始点或者调用对应的便捷方法。
- 当你想要闭合当前路径,调用 CGContextClosePath方法来连接上起始点。
- 当你绘制弧时,Quartz会在当前点和弧的起始点之间绘制一条直线。
- 最后需调用绘制函数来填充(fill)或画(stroke)出路径。
如:
CGContextMoveToPoint(context, 100, 100);
CGContextAddLineToPoint(context, 200, 200);
CGContextAddLineToPoint(context, 50, 300);
CGContextClosePath(context);
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
CGContextStrokePath(context);
当路径被绘制出来后,路径会被清除。如果想要保存路径,Quartz提供了两种数据类型来创建可重复利用的路径:CGPathRef 和 CGMutablePathRef。但操作的是CGPath而不是graphics context:
- CGPathCreateMutable 代替 CGContextBeginPath
- CGPathMoveToPoint 代替 CGContextMoveToPoint
- CGPathAddLineToPoint 代替 CGContextAddLineToPoint
- CGPathAddCurveToPoint 代替 CGContextAddCurveToPoint
- CGPathAddEllipseInRect 代替 CGContextAddEllipseInRect
- CGPathAddArc 代替 CGContextAddArc
- CGPathAddRect 代替 CGContextAddRect
- CGPathCloseSubpath 代替 CGContextClosePath
###Painting a Path###
Quartz提供方法画出(画线)或填充路径,或者同时画出(画线)并填充路径。绘制的线条特性(宽度、颜色等)、填充颜色和计算填充区域的方式都是graphics state的一部分。
可以通过下表的属性,修改画出的路径特性。一旦修改这些属性,会作用于之后的所有绘制中。
Parameter | Function to set parameter value |
---|---|
Line width | CGContextSetLineWidth |
Line join | CGContextSetLineJoin |
Line cap | CGContextSetLineCap |
Miter limit | CGContextSetMiterLimit |
Line dash pattern | CGContextSetLineDash |
Stroke color space | CGContextSetStrokeColorSpace |
Stroke color | CGContextSetStrokeColorCGContextSetStrokeColorWithColor |
Stroke pattern | CGContextSetStrokePattern |
line width是线条的宽度,路径两边各占线宽的一半。
line join表示Quartz怎么处理线条的连接处。Quartz支持的连接样式 如下:
line cap表示线的两个端点的样式:
line dash线条的样式:
Quartz提供的画线方法:
Function | Description |
---|---|
CGContextStrokePath | Strokes the current path. |
CGContextStrokeRect | Strokes the specified rectangle. |
CGContextStrokeRectWithWidth | Strokes the specified rectangle, using the specified line width. |
CGContextStrokeEllipseInRect | Strokes an ellipse that fits inside the specified rectangle. |
CGContextStrokeLineSegments | Strokes a sequence of lines. |
CGContextDrawPath | If you pass the constant kCGPathStroke, strokes the current path. See Filling a Path if you want to both fill and stroke a path. |
###Filling a Path###
当填充路径时,Quartz认为每一个路径都是闭合的,然后利用这些闭合的路径计算填充区域。一共有两种计算填充区域的方式。椭圆形、矩形等简单的路径,很好确定填充区域。但是如果有重叠的路径或者路径内包含多个路径时(如下图),有两种规则来确定填充区域。
默认的填充规则为非零绕组规则:给定一条曲线C和一个点P,构造一条从P点出发射向无穷远的射线。找出所有该射线和曲线的交点,并按如下规则统计绕组数量(winding number):每一个顺时针方向(曲线从左向右通过射线)上的交点减1,每一个逆时针方向(曲线从右向左通过射线)上的交点加1。如果绕组总数为0,表示该点在曲线外;否则,该点在曲线内。
另一个为奇偶规则。平面内的任何一点P,引出一条射线,注意不要经过多边形的顶点,如果射线与多边形的交点的个数为奇数,则点P在多边形的内部,如果交点的个数为偶数,则点P在多边形的外部。
(参考:http://blog.csdn.net/wodownload2/article/details/52151714)
【实例】中间透明的引导蒙层
http://blog.csdn.net/dolacmeng/article/details/79285679
Quartz提供的填充函数如下3-5:
Function | Description |
---|---|
CGContextEOFillPath | Fills the current path using the even-odd rule. |
CGContextFillPath | Fills the current path using the nonzero winding number rule. |
CGContextFillRect | Fills the area that fits inside the specified rectangle. |
CGContextFillRects | Fills the areas that fits inside the specified rectangles. |
CGContextFillEllipseInRect | Fills an ellipse that fits inside the specified rectangle. |
CGContextDrawPath | Fills the current path if you pass kCGPathFill (nonzero winding number rule) or kCGPathEOFill (even-odd rule). Fills and strokes the current path if you pass kCGPathFillStroke or kCGPathEOFillStroke. |
###Setting Blend Modes###
重叠模式,两个绘制重叠时,重叠部分默认的颜色为:
result = (alpha * foreground) + (1 - alpha) * background
###Clipping to a Path###
路径可以作为遮罩,进行裁剪。例如有一张大图,但只希望显示其中一部分,可以设置裁剪区域,即只显示在闭合路径内部的部分:
CGContextBeginPath (context);
CGContextAddArc (context, w/2, h/2, ((w>h) ? h : w)/2, 0, 2*PI, 0);
CGContextClosePath (context);
CGContextClip (context);
提供的裁剪方法:
Function | Description |
---|---|
CGContextClip | Uses the nonzero winding number rule to calculate the intersection of the current path with the current clipping path. |
CGContextEOClip | Uses the even-odd rule to calculate the intersection of the current path with the current clipping path. |
CGContextClipToRect | Sets the clipping area to the area that intersects both the current clipping path and the specified rectangle. |
CGContextClipToRects | Sets the clipping area to the area that intersects both the current clipping path and region within the specified rectangles. |
CGContextClipToMask | Maps a mask into the specif |
###Transforms###
在绘图前,可以通过变换矩阵(CTM)进行旋转、缩放、移动(可以理解为对坐标系操作),从而实现对即将绘制的图像进行变换。
下面的代码会把一张图片绘制到上下文:
CGContextDrawImage (myContext, rect, myImage);
//在iOS中,因为UIKit坐标系统和Quartz坐标系统不一样,需要先调用CTM变换再绘图CGContextTranslateCTM(context, 0, rect.size.height);CGContextScaleCTM(context, 1.0, -1.0);
调用CGContextTranslateCTM函数,改变坐标空间原点的x和y,如在x轴上移动100个单位,在y轴上移动50个单位:
CGContextTranslateCTM (myContext, 100, 50);
调用CGContextRotateCTM来旋转坐标系。如,旋转-45度:
CGContextRotateCTM (myContext, radians(–45.));
此时部分图片内容被裁剪了,因为这部分被移到图形上下文之外了。另外需要将角度转换为弧度:
include <math.h>static inline double radians (double degrees) {return degrees * M_PI/180;}
调用CGContextScaleCTM可以在x轴和y轴上对坐标系进行缩放,如果为负值,可以进行翻转。例如在x轴上缩放0.5倍,在y轴上缩放0.75倍:
可以结合使用多个变换,通过CGContextConcatCTM方法可将多个变换组合成一个变换。
也可以直接依次执行多个变换。如:
CGContextTranslateCTM (myContext, w/4, 0);
CGContextScaleCTM (myContext, .25, .5);
CGContextRotateCTM (myContext, radians ( 22.));
###Creating Affine Transforms###
仿射变换(affine transform)是作用于矩阵而非CTM。可以使用这些函数构造一个矩阵,然后通过函数CGContextConcatCTM应用于CTM。
仿射变换和CTM变换作用相同,都可以进行平移、旋转、缩放操作。方法和作用如下表:
Function | Use |
---|---|
CGAffineTransformMakeTranslation | To construct a new translation matrix from x and y values that specify how much to move the origin. |
CGAffineTransformTranslate | To apply a translation operation to an existing affine transform. |
CGAffineTransformMakeRotation | To construct a new rotation matrix from a value that specifies in radians how much to rotate the coordinate system. |
CGAffineTransformRotate | To apply a rotation operation to an existing affine transform. |
CGAffineTransformMakeScale | To construct a new scaling matrix from x and y values that specify how much to stretch or shrink coordinates. |
CGAffineTransformScale | To apply a scaling operation to an existing affine transform. |
.
Quartz提供了CGAffineTransformInvert方法来撤消一个矩阵。但一般可以通过保存和还原graphics state实现类似的需求。
如果想要只对某个点或某部分进行变换,可以通过CGPointApplyAffineTransform方法对点,通过CGSizeApplyAffineTransform对某部分进行操作。
【待续…】
参考:
https://developer.apple.com/library/content/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_overview/dq_overview.html
相关文章:
有关运维面试重点
数据库分为:关系型数据库(mysql、mariadb)和非关系型数据库(redis等) mysql主从复制的原理: 主从复制: master开启binlog日志master和slave的server-id不同slave主动连接master mysql复制是将…
微信应用号开发知识贮备之altjs官方实例初探
天地会珠海分舵注:随着微信应用号的呼之欲出,相信新一轮的APP变革即将发生。从获得微信应用号邀请的业内人士发出来的一张开发工具源码截图可以看到,reacjs及其相应的FLUX框架altjs很有可能会成为前端开发主流。作为行业内人士,自己之前从来没…

Oracle DMP 操作笔记之根据DMP逆向推导出导出的表空间名称
最近在带着一群.NET新兵们在开发和升级一套系统,本人虽然工作好几年,但是也是属于啥都懂一点,啥都不会的队伍,碰到新兵更是蛋都碎了,还特别拘谨,为啥新兵们都是基础知识很不错的,看来要好好练习…
【iOS】中间透明的引导蒙层
需求 如图口袋蜜蜂app一键海报的新手指引图,需求是遮罩层中间透明的,把底层的第一张海报显示出来,如图: 实现 通过UIBezierPath和CAShapeLayer绘制一张中间为透明的黑色半透明遮罩层。 步奏1、新建类PCOnePosterGuide继承自…

python连接数据库,处理数据结果后生成excel文件
# _*_coding:utf-8 _*_ import time import xlwt import os import pymysql import sys import datetime from datetime import datetime, timedelta class writefile: file r"D:\Users\xx\Desktop" #查询数据库结果 def datacommon(self,mounth,day,n,abj)…

WhyGL:一套学习OpenGL的框架,及翻写Nehe的OpenGL教程
最近在重学OpenGL,之所以说重学是因为上次接触OpenGL还是在学校里,工作之后就一直在搞D3D,一转眼已经毕业6年了.OpenGL这门手艺早就完全荒废了,现在只能是重学.学习程序最有效的办法是动手写,光看书是不行了,因为看书的时候很容易陷入对人类两大难题的思考中,以至于进展缓慢.这…

iOS与JS交互的4种方法
iOS与JS交互的方法: 1.拦截url(适用于UIWebView和WKWebView) 2.JavaScriptCore(只适用于UIWebView,iOS7) 3.WKScriptMessageHandler(只适用于WKWebView,iOS8) 4.WebV…

UDP打洞原理
1. NAT分类根据Stun协议(RFC3489),NAT大致分为下面四类1) Full Cone这种NAT内部的机器A连接过外网机器C后,NAT会打开一个端口.然后外网的任何发到这个打开的端口的UDP数据报都可以到达A.不管是不是C发过来的.例如 A:192.168.8.100 NAT:202.100.100.100 C:292.88.88.88A(192.168…

五款常用协议分析处理工具推荐
工欲善其事,必先利其器,一款好的工具,能取到事半功倍的效果。进行协议分析,好的辅助工具必不可少,本文推荐五款最常用且易用的协议分析工具给大家,包括两款综合抓包及分析工具,一款协议重放工具…
【转】android电池(四):电池 电量计(MAX17040)驱动分析篇
关键词:android 电池 电量计 MAX17040 任务初始化宏 power_supply 平台信息:内核:linux2.6/linux3.0系统:android/android4.0 平台:samsung exynos 4210、exynos 4412 、exynos 5250 作者:xubin341719(欢迎转载&…

hihoCoder#1384 : Genius ACM
对于一个固定的区间$[l,r]$,显然只要将里面的数字从小到大排序后将最小的$m$个和最大的$m$个配对即可。 如果固定左端点,那么随着右端点的右移,$SPD$值单调不降,所以尽量把右端点往右移,贪心分割即可。 为了使得扫过的…

微信小程序开发 笔记
1.[wxss]设置带透明度的rgb颜色:rgb(0,0,0,0.5); 2.小程序使用类似于iOS的NSNotification:(第三方:https://github.com/icindy/WxNotificationCenter) (1)在需要收发通知的页面引入WxNotificationCenter: var WxNotifi…

简单两行,实现无线WiFi共享上网,手机抓包再也不用愁了
你是否为WiFi共享而发愁,各个无线共享软件,某某共享精灵,某某免费WiFi,某某共享大师,某某随身WiFi,一个比一个难用,一个比一个私货多,一个比一个广告多,如果装上了它们&a…

用C#实现的条形码和二维码编码解码器
本篇介绍可以在C#中使用的1D/2D编码解码器。条形码的应用已经非常普遍,几乎所有超市里面的商品上面都印有条形码;二维码也开始应用到很多场合,如火车票有二维码识别、网易的首页有二维码图标,用户只需要用手机扫描一下就可以看到手…
【iOS】通过NSURLProtocol提高Web加载速度
一.项目需求 项目中有个海报功能,是用UIWebView加载h5网页的形式。因为海报的使用率比较高,如果网页加载得比较慢会严重影响用户体验,因此我们想了一个方法,在用户启动APP后,如果连接了Wi-Fi,就将一些css和…

rand()和srand()关系很简单——一看就明白(通过一个可移植的源码)
1 函数rand和srand实现及描述 #include <stdlib.h> //供rand()使用的种子数,初值为1 unsigned long int next 1; /* * 描述:函数rand() 用于生成介于 0和RAND_MAX之间的伪随机整数序列 * 其中RAND_MAX是在头文件<stdlib.h> 中定义的…

Windows下Python 3.6 安装BeautifulSoup库
“ 介绍Python库BeautifulSoup安装。”01—BeautifulSoup库介绍Beautiful Soup是Python的一个库,支持Python 2和Python 3,最主要的功能是从网页抓取数据,即爬虫,官网介绍如下:Beautiful Soup provides a few simple methods and Pythonic idi…

struts2配置详解
01.Struts 2基本结构 使用Struts2框架实现用登录的功能,使用struts2标签和ognl表达式简化了试图的开发,并且利用struts2提供的特性对输入的数据进行验证,以及访问ServletAPI时实现用户会话跟踪,其简单的程序运行流程图如下 Struts…
Xcode调试技巧
1、给断点设定触发条件 如下代码,右键断点,选择Edit Breakpoint,设定只有i8时,才触发断点。 此时只有i8时,才触发断点。 2、断点调试时修改变量 上面代码i8成立时,触发短点,此时右击变量窗口…

MiniGUI - UNIX Domain Socket 封装
/* Returns fd if all OK, -1 on error. */ int serv_listen (const char* name);服务器调用该函数建立一个监听套接字,并返回套接字文件描述符。建议将服务器监听套接字建立在 /var/tmp/ 目录下。MAX_NR_LISTEN_FD 宏定义了系统能够监听的最多文件描述符数…

RSA加密算法破解及原理
“ RSA加密算法是一种非对称加密算法,目前被广泛应用。本文介绍RSA算法的基本原理和破解方法。”RSA在互联网上被广泛应用,典型的如各个网站的证书。很多应用数据的加密也是使用RSA。本文介绍RSA算法的原理,并介绍其破解方法和工具。01—RSA算…

SpringMvc之@RequestParam详解
RequestParam是传递参数的. RequestParam用于将请求参数区数据映射到功能处理方法的参数上。 public String queryUserName(RequestParam String userName) 在url中输入:localhost:8080/**/?userNamezhangsan 请求中包含username参数(如/requestparam1?userNamezh…

MLeaksFinder简单实现原理
MLeaksFinder是 iOS 平台的自动内存泄漏检测工具,下面以demo来实现检测视图控制器是否内存泄漏,实现类似的功能,简单地了解MLeaksFinder的原理。 总体思路:在视图控制器弹出栈 && 视图完全消失时,监听对象是否…

CSipSimple 工程分析 1
有两种方法,但是个人只有一种方法可以实现build并且生成应用,那么就是直接下载Google Code CSipSimple中提供已经设置好所有的配置的额\ubuntu虚拟机镜像文件. 打开这个镜像文件需要virtual Box,这个在oracle官方网站上面有,是个免费开源的软件. Google Code : https://code.go…

干货,Wireshark使用技巧-过滤规则
“介绍Wireshark抓包时使用的过滤规则。”熟练使用Wireshark,对协议分析大有帮助。本文介绍抓取报文时使用的过滤规则和对已有报文的显示进行控制的显示规则。01—过滤规则使用在抓取报文时使用的规则,称为过滤规则,Wireshark底层是基于Winpc…
《图解HTTP》笔记之TCP/IP
TCP/IP 通常使用的网络(包括互联网)是在TCP/IP协议族的基础上运作的。把互联网相关联的协议集合起来总称为TCP/IP。而HTTP属于它内部的一个子集(HTTP协议是建立在TCP协议之上的一种应用): TCP/IP协议族里最重要的一…

JS --正则表达式验证、实战之邮箱模式
JS验证格式:提高用户体验,验证文本。需要防止程序员的代码结构更改攻击,因为web段的代码有可能会被更改,更改后JS有可能会验证不住那么,C#端在JS段通过验证的情况下,还需要进行二次验证 <body><fo…

《ASP.NET MVC4 WEB编程》学习笔记------Web API 续
目录 ASP.NET WEB API的出现缘由 ASP.NET WEB API的强大功能 ASP.NET WEB API的出现缘由 随着UI AJAX 请求适量的增加,ASP.NET MVC基于JsonResult的控制器操作将无法满足高级AJAX前端的需求。如果真的出现这种情况,就应该好好寻找一种更简单,…

干货:Wireshark使用技巧-显示规则
“ 介绍Wireshark对已有报文的显示进行控制的显示规则。”之前对Wireshark抓包时使用的过滤规则进行了介绍,本文介绍对已有报文的显示进行控制的显示规则。掌握了显示规则,你使用Wireshark的动作都会炫起来。点击回顾:过滤规则01—显示规则使…

【转载】Linux系统与性能监控
原文: Linux System and Performance Monitoring Darren Hoch 译:Roger 这是[叔度]给我的一篇非常不错的关于Linux性能监控的文档,可惜是英文的,网上只能找到些中文节选,并不完整。 准备花些时间将原文共43页认真学习一下,顺便翻译…