iOS中 CoreGraphics快速绘图(详解) 韩俊强的博客
每日更新关注:http://weibo.com/hanjunqiang
新浪微博
第一步:先科普一下基础知识:
Core Graphics是基于C的API,可以用于一切绘图操作
Core Graphics 和Quartz 2D的区别
quartz是一个通用的术语,用于描述在IOS和MAC OS X ZHONG 整个媒体层用到的多种技术 包括图形、动画、音频、适配。
Quart 2D 是一组二位绘图和渲染API,Core Graphic会使用到这组API
Quartz Core 专指Core Animation用到的动画相关的库、API和类
点和像素的对比
系统拥有坐标系,如320*480 硬件有retain屏幕和非retain屏:如320*480、640*960
Core Graphics 使用的是系统的坐标系来绘制图片。在分辨率为640*960手机上绘制图片时,实际上Core Graphics 的坐标是320*480。这个时候每个坐标系上的点,实际上拥有两个像素。
图形上下文
Core Graphics 使用图形上下文进行工作,这个上下文的作用像画家的画布一样。
在图形上下文之外是无法绘图的,我们可以自己创建一个上下文,但是性能和内存的使用上,效率是非常低得。
我们可以通过派生一个UIView的子类,获得它的上下文。在UIView中调用drawRect:方法时,会自动准备好一个图形上下文,可以通过调用
UIGraphicsGetCurrentContext()来获取。 因为它是运行期间绘制图片,我们可以动态的做一些额外的操作
Core Graphics的优点
快速、高效,减小应用的文件大小。同时可以自由地使用动态的、高质量的图形图像。 使用Core Graphics,可以创建直线、路径、渐变、文字与图像等内容,并可以做变形处理。
绘制自定义视图
drawRect:是系统的方法,不要从代码里面直接调用 drawRect:,而应该使用setNeedsDisplay重绘.
需要知道的术语
- 路径 path
- 阴影 shadow
- 笔画 stroke
- 剪裁路径 Clip Path
- 线条粗细 Line Width
- 混合模式 Blend Mode
- 填充色 Fill Color
- 当前形变矩阵 Current Transform Matrix
- 线条图案 Line Dash
图形上下文栈
一个图形上下文好比是画布上的一副扁平的图画 执行绘画动作,这些动作是在同一个图层上完成的。 图形上下文不允许将内容分不到多个图层中,如果有需求在不同图层上画,可以考虑使用视图层次结构,创建多个UIView,并将他们作为父视图的子视图
图形上下文栈可以把图形上下文的当前状态保存下来,并在执行一些动作后再次恢复回来
CGContextSaveGState();
CGContextStoreGState();
路径、渐变、文字和图像
1. 使用UIBezierPath创建路径
2. 手动创建路径 moveToPoint addLineToPoint addArcWithCenter addCurveToPoint
渐变,渐变可以在指定方向上,以可变的比率在一系列颜色之间转化
线性渐变:沿着一条定义好了起点和重点的直线方向,呈线性变化。如果这条线有一定角度,线性渐变也会沿相同路径变化
放射渐变:颜色顺着两个原型之间的方向线性变化,这两个园为起始圆和终止圆,每隔圆都有自己的圆心和班级
文字
darwAtPoint
drawInRect
图像
Core Graphics 不会保持图像的长宽比例,Core Graphics会将图像的边界设置为CGrect,不管图片是否变形 darwAtPoint drawInRect
第二步:代码部分:
基础画法就不多讲啦!都通用:
- (void) drawRect: (CGRect) rect { UIBezierPath* p = [UIBezierPathbezierPathWithOvalInRect:CGRectMake(0,0,100,100)]; [[UIColor blueColor] setFill]; [p fill]; }
- (void) drawRect: (CGRect) rect { CGContextRef con = UIGraphicsGetCurrentContext(); CGContextAddEllipseInRect(con, CGRectMake(0,0,100,100)); CGContextSetFillColorWithColor(con, [UIColor blueColor].CGColor); CGContextFillPath(con); }
@interface MyLayerDelegate : NSObject @end
@implementation MyLayerDelegate - (void)drawLayer:(CALayer*)layer inContext:(CGContextRef)ctx { UIGraphicsPushContext(ctx); UIBezierPath* p = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0,0,100,100)]; [[UIColor blueColor] setFill]; [p fill]; UIGraphicsPopContext(); } @end
@interface MyView () { MyLayerDelegate* _layerDeleagete; } @end
MyView *myView = [[MyView alloc] initWithFrame: CGRectMake(0, 0, 320, 480)]; CALayer *myLayer = [CALayer layer]; _layerDelegate = [[MyLayerDelegate alloc] init]; myLayer.delegate = _layerDelegate; [myView.layer addSublayer:myLayer]; [myView setNeedsDisplay]; // 调用此方法,drawLayer: inContext:方法才会被调用。
- (void)drawLayer:(CALayer*)lay inContext:(CGContextRef)con { CGContextAddEllipseInRect(con, CGRectMake(0,0,100,100)); CGContextSetFillColorWithColor(con, [UIColor blueColor].CGColor); CGContextFillPath(con); }
UIGraphicsBeginImageContextWithOptions(CGSizeMake(100,100), NO, 0); UIBezierPath* p = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0,0,100,100)]; [[UIColor blueColor] setFill]; [p fill]; UIImage* im = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext();
UIGraphicsBeginImageContextWithOptions(CGSizeMake(100,100), NO, 0); CGContextRef con = UIGraphicsGetCurrentContext(); CGContextAddEllipseInRect(con, CGRectMake(0,0,100,100)); CGContextSetFillColorWithColor(con, [UIColor blueColor].CGColor); CGContextFillPath(con); UIImage* im = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext();
第三步:实践部分:
第一种:基本图形绘制
/** * 什么调用:当你视图第一次显示的时候就会调用 * 作用:绘图 * @param rect = self.bounds */ - (void)drawRect:(CGRect)rect { // 1.获取上下文 CGContextRef ctx = UIGraphicsGetCurrentContext(); // 2.拼接路径 UIBezierPath *path = [UIBezierPath bezierPath]; CGPoint startP = CGPointMake(10, 125); CGPoint endP = CGPointMake(240, 125); CGPoint controlP = CGPointMake(125, 0); [path moveToPoint:startP]; [path addQuadCurveToPoint:endP controlPoint:controlP]; // 3.把路径添加到上下文 CGContextAddPath(ctx, path.CGPath); // 4.渲染上下文到视图 CGContextStrokePath(ctx); } - (void)drawLine { // 1.获取上下文 // CGContextRef CG CoreGraphics Ref 引用 // 目前学的上下文都跟UIGraphics有关,以后想直接获取上下文,直接敲一个UIGraphics CGContextRef ctx = UIGraphicsGetCurrentContext(); // 2.设置绘图信息(拼接路径) UIBezierPath *path = [UIBezierPath bezierPath]; // 设置起点 [path moveToPoint:CGPointMake(10, 10)]; // 添加一条线到某个点 [path addLineToPoint:CGPointMake(125, 125)]; [path addLineToPoint:CGPointMake(240, 10)]; // 3.把路径添加到上下文 // 直接把UIKit的路径转换成CoreGraphics,CG开头就能转 CGContextAddPath(ctx, path.CGPath); // 4.把上下文渲染到视图 // Stroke描边 CGContextStrokePath(ctx); } - (void)draw2Line { // 1.获取上下文 CGContextRef ctx = UIGraphicsGetCurrentContext(); // 2.拼接路径 UIBezierPath *path = [UIBezierPath bezierPath]; // 设置起点 [path moveToPoint:CGPointMake(10, 125)]; // 添加一条线到某个点 [path addLineToPoint:CGPointMake(230, 125)]; // // 设置起点 // [path moveToPoint:CGPointMake(10, 10)]; // // // 添加一条线到某个点 // [path addLineToPoint:CGPointMake(125, 100)]; UIBezierPath *path1 = [UIBezierPath bezierPath]; [path1 moveToPoint:CGPointMake(10, 10)]; [path1 addLineToPoint:CGPointMake(125, 100)]; // 3.把路径添加到上下文 CGContextAddPath(ctx, path.CGPath); CGContextAddPath(ctx, path1.CGPath); // 设置绘图状态 // 设置线宽 CGContextSetLineWidth(ctx, 10); CGContextSetLineCap(ctx, kCGLineCapRound); // CGContextSetRGBStrokeColor(ctx, 1, 0, 0, 1); [[UIColor redColor] set]; // 4.渲染上下文到视图 CGContextStrokePath(ctx); }
每日更新关注:http://weibo.com/hanjunqiang
新浪微博
第二种:下载进度条:
- (void)setProgress:(CGFloat)progress { _progress = progress; self.myLabel.text = [NSString stringWithFormat:@"%.2f%%",progress*100]; // [self drawRect:self.bounds]; // 重新绘制 // 在view上做一个重绘的标记,当下次屏幕刷新的时候,就会调用drawRect. [self setNeedsDisplay]; } // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. // 当视图显示的时候会调用 默认只会调用一次 - (void)drawRect:(CGRect)rect { // 1.获取上下文 CGContextRef ctx = UIGraphicsGetCurrentContext(); // 2.拼接路径 CGPoint center = CGPointMake(50, 50); CGFloat radius = 50 - 2; CGFloat startA = -M_PI_2; CGFloat endA = -M_PI_2 + _progress * M_PI * 2; UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:YES]; // 3.把路径添加到上下文 CGContextAddPath(ctx, path.CGPath); // 4.把上下文渲染到视图 CGContextStrokePath(ctx); }
每日更新关注:http://weibo.com/hanjunqiang
新浪微博
第三种:饼图
- (void)drawRect:(CGRect)rect { // Drawing code NSArray *data = @[@25,@25,@50]; // 1.获取上下文 CGContextRef ctx = UIGraphicsGetCurrentContext(); // 2.拼接路径 CGPoint center = CGPointMake(125, 125); CGFloat radius = 120; CGFloat startA = 0; CGFloat angle = 0; CGFloat endA = 0; for (NSNumber *number in data) { // 2.拼接路径 startA = endA; angle = number.intValue / 100.0 * M_PI * 2; endA = startA + angle; UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:YES]; [path addLineToPoint:center]; [[UIColor randomColor] set]; // 把路径添加上下文 CGContextAddPath(ctx, path.CGPath); // 渲染 CGContextFillPath(ctx); } } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { CGFloat a = arc4random_uniform(6); //CGFloat a = arc4random()%6; NSLog(@"随机数--%f",a); [self setNeedsDisplay]; } - (void)drawPie { // 1.获取上下文 CGContextRef ctx = UIGraphicsGetCurrentContext(); // 2.拼接路径 CGPoint center = CGPointMake(125, 125); CGFloat radius = 120; CGFloat startA = 0; CGFloat angle = 0; CGFloat endA = 0; // 第一个扇形 angle = 25 / 100.0 * M_PI * 2; endA = startA + angle; UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:YES]; [path addLineToPoint:center]; // 添加到上下文 CGContextAddPath(ctx, path.CGPath); [[UIColor redColor] set]; // 渲染 CGContextFillPath(ctx); // 第二个扇形 startA = endA; angle = 25 / 100.0 * M_PI * 2; endA = startA + angle; UIBezierPath *path1 = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:YES]; [path1 addLineToPoint:center]; // 添加到上下文 CGContextAddPath(ctx, path1.CGPath); [[UIColor greenColor] set]; // 渲染 CGContextFillPath(ctx); // 第三个扇形 startA = endA; angle = 50 / 100.0 * M_PI * 2; endA = startA + angle; UIBezierPath *path2 = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:YES]; [path2 addLineToPoint:center]; // 添加到上下文 CGContextAddPath(ctx, path2.CGPath); [[UIColor blueColor] set]; // 渲染 CGContextFillPath(ctx); }
每日更新关注:http://weibo.com/hanjunqiang
新浪微博
第四种:柱形图
- (void)drawRect:(CGRect)rect { NSArray *data = @[@25,@25,@50]; NSInteger count = data.count; CGFloat w = rect.size.width / (2 * count - 1); CGFloat h = 0; CGFloat x = 0; CGFloat y = 0; CGFloat viewH = rect.size.height; // 1.获取上下文 CGContextRef ctx = UIGraphicsGetCurrentContext(); for (int i = 0; i < count; i++) { h = viewH * [data[i] intValue] / 100.0; x = 2 * w * i; y = viewH - h; // 2.拼接路径 UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(x, y, w, h)]; // 3.添加路径到上下文 CGContextAddPath(ctx, path.CGPath); [[UIColor randomColor] set]; // 4.渲染 CGContextFillPath(ctx); } } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [self setNeedsDisplay]; }
每日更新关注:http://weibo.com/hanjunqiang
新浪微博
第五种:模仿UIImageView
- (void)setImage:(UIImage *)image { _image = image; [self setNeedsDisplay]; } // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code [_image drawInRect:rect]; }
每日更新关注:http://weibo.com/hanjunqiang
新浪微博
第六种:图形上下文线
- (void)drawRect:(CGRect)rect { // Drawing code // 1.获取上下文 CGContextRef ctx = UIGraphicsGetCurrentContext(); // 把ctx拷贝一份放在栈中 CGContextSaveGState(ctx); // 2.拼接路径(绘图的信息) UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:CGPointMake(10, 125)]; [path addLineToPoint:CGPointMake(240, 125)]; // 3.路径添加到上下文 CGContextAddPath(ctx, path.CGPath); // 设置绘图的状态 [[UIColor redColor] set]; CGContextSetLineWidth(ctx, 10); CGContextSetLineCap(ctx, kCGLineCapRound); // 4.渲染 CGContextStrokePath(ctx); // 第二根线 UIBezierPath *path1 = [UIBezierPath bezierPath]; [path1 moveToPoint:CGPointMake(125, 10)]; [path1 addLineToPoint:CGPointMake(125, 240)]; CGContextAddPath(ctx, path1.CGPath); // 把栈顶上下文取出来,替换当前上下文 CGContextRestoreGState(ctx); // 设置绘图的状态 // [[UIColor blackColor] set]; // CGContextSetLineWidth(ctx, 1); // CGContextSetLineCap(ctx, kCGLineCapButt); // 4.渲染 CGContextStrokePath(ctx); }
每日更新关注:http://weibo.com/hanjunqiang
新浪微博
第七种:矩形操作
- (void)drawRect:(CGRect)rect { // Drawing code // 1.获取上下文 CGContextRef ctx = UIGraphicsGetCurrentContext(); // 注意:你的路径一定放在上下文矩阵操作之后 // 平移上下文 CGContextTranslateCTM(ctx, 50, 100); // 旋转上下文 CGContextRotateCTM(ctx, M_PI_4); // 缩放上下文 CGContextScaleCTM(ctx, 0.5, 1.2); // 2.拼接路径 UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(-50, -100, 150, 200)]; // 3.把路径添加到上下文 CGContextAddPath(ctx, path.CGPath); [[UIColor redColor] set]; // 4.渲染 CGContextFillPath(ctx); }
每日更新关注:http://weibo.com/hanjunqiang
新浪微博
iOS开发者交流QQ群: 446310206 欢迎加入(demo在这里)!
iOS中 CoreGraphics快速绘图(详解) 韩俊强的博客的更多相关文章
- iOS中 扫描二维码/生成二维码详解 韩俊强的博客
最近大家总是问我有没有关于二维码的demo,为了满足大家的需求,特此研究了一番,希望能帮到大家! 每日更新关注:http://weibo.com/hanjunqiang 新浪微博 指示根视图: se ...
- iOS中 HTTP/Socket/TCP/IP通信协议详解 韩俊强的博客
每日更新关注:http://weibo.com/hanjunqiang 新浪微博 简单介绍: // OSI(开放式系统互联), 由ISO(国际化标准组织)制定 // 1. 应用层 // 2. 表示层 ...
- iOS中 本地通知/本地通知详解 韩俊强的博客
布局如下:(重点讲本地通知) iOS开发者交流QQ群: 446310206 每日更新关注:http://weibo.com/hanjunqiang 新浪微博 Notification是智能手机应用编 ...
- iOS中 Realm的学习与使用 韩俊强的博客
每日更新关注:http://weibo.com/hanjunqiang 新浪微博! 有问题或技术交流可以咨询!欢迎加入! 这篇直接搬了一份官方文档过来看的 由于之前没用markdown搞的乱七八糟的 ...
- iOS中 最新微信支付/最全的微信支付教程详解 韩俊强的博客
每日更新关注:http://weibo.com/hanjunqiang 新浪微博! 亲们, 首先让我们来看一下微信支付的流程吧. 1. 注册微信开放平台,创建应用获取appid,appSecret, ...
- iOS中 语音识别功能/语音转文字教程详解 韩俊强的博客
每日更新关注:http://weibo.com/hanjunqiang 新浪微博 原文地址:http://blog.csdn.net/qq_31810357/article/details/5111 ...
- iOS中 蓝牙2.0详解/ios蓝牙设备详解 韩俊强的博客
每日更新关注:http://weibo.com/hanjunqiang 新浪微博 整体布局如下: 程序结构如右图: 每日更新关注:http://weibo.com/hanjunqiang ...
- iOS中 断点下载详解 韩俊强的博客
布局如下: 基本拖拉属性: #import "ViewController.h" #import "AFNetworking.h" @interface Vie ...
- iOS中 自定义cell分割线/分割线偏移 韩俊强的博客
在项目开发中我们会常常遇到tableView 的cell分割线显示不全,左边会空出一截像素,更有甚者想改变系统的分割线,并且只要上下分割线的一个等等需求,今天重点解决以上需求,仅供参考: 每日更新关注 ...
随机推荐
- 【集训第四天·继续刷题】之 lgh怒刚ypj
继续水题,终于完全掌握了伸展树了,好心痛QAQ. 1.codevs1343 蚱蜢 区间最大值查询+单点移动 最大值查询维护一个mx数组就行,单点移动么,先删除在插入 CODE: /* PS: 比较ma ...
- 配置mysql使其允许外部ip进行登录
这两天在做一个数据库的项目,用到了mysql,需要通过外部的ip远程访问mysql,发现默认的mysql是不允许远程访问的,需要做简单的配置. 如下: 1. 打开一个终端(cmd)输入 mysql - ...
- c++中成员函数的参数名与成员变量名重合的问题
有一天写类的时候突然想到了这个问题,下面就来介绍如何解决这个问题. 定义一个类: class test{ public: void setnum(); void getnum(); private: ...
- Hibernate的条件查询的几种方式
1. 第一种,用?占位符,如: //登录(用?占位符) public List<UserPO> LoginUser(UserPO up)throws Exception{ Session ...
- linux系统下安装jdk、tomcat、mysql、redis
一,安装jdk 1.rpm -qa | grep jdk 检测是否安装jdk 2.rpm -e --nodeps 要卸载的已有jdk名称 3.tar -zxvf jdk-7u71-linux-i586 ...
- 各种电子面单Api接口免费对接-快宝开放平台
1.什么是电子面单? 快递公司联合向商家提供的一种通过热敏纸打印输出纸质物流面单的物流服务,并且承载分单自动化算法等数据服务,是快递行业赋能的基础产品和服务. 2.电子面单长什么样? 各快递公司有自己 ...
- Hadoop — MapReduce原理解析
1. 概述 Mapreduce是一个分布式运算程序的编程框架,是用户开发"基于hadoop的数据分析应用"的核心框架: Mapreduce核心功能是将用户编写的业务逻辑代码和自带默 ...
- 小知识点 取消button动作 和取巧按钮高亮
如果让按钮在点击时不变暗 进行下面设置: 如果使butten失去动画效果进行下面设置:(一般用于图片+文字,效果等于可以加图片班的label,当然label不能加图片)
- ACM 排列2
Ray又对数字的列产生了兴趣: 现有四张卡片,用这四张卡片能排列出很多不同的4位数,要求按从小到大的顺序输出这些4位数. Input每组数据占一行,代表四张卡片上的数字(0<=数字<=9 ...
- Node.js 进程
process 是全局对象,能够在任意位置访问,是 EventEmitter 的实例. 退出状态码 当没有新的异步的操作等待处理时,Node 正常情况下退出时会返回状态码 0 .下面的状态码表示其他状 ...