Quartz 2D是一个二维绘图引擎,同时支持iOS和Mac系统
Quartz 2D能完成的工作
绘制图形 : 线条/三角形/矩形/圆/弧等
绘制文字
绘制/生成图片(图像)
读取/生成PDF
截图/裁剪图片
自定义UI控件
自定义 view 的步骤
1、新建一个类,继承自 UIView
2、实现 - ( void )drawRect:(CGRect)rect 方法,然后在这个方法中
3、取得跟当前 view 相关联的图形上下文
4、绘制相应的图形内容
5、利用图形上下文将绘制的所有内容渲染显示到 view 上面
#pragma mark - 最原始的绘图方式 1
- ( void )draw2 {
// Drawing code
// 获得图形上下文
CGContextRef con = UIGraphicsGetCurrentContext ();
// 创建路径
CGMutablePathRef path = CGPathCreateMutable ();
// 绘制一条线
// CGPathMoveToPoint(path, NULL, 50, 50);
// CGPathAddLineToPoint(path, NULL, 200, 200);
// 绘制矩形
// CGPathAddRect(path, NULL, CGRectMake(60, 60, 100, 100));
// CGPathAddEllipseInRect(path, NULL, CGRectMake(60, 60, 100, 100));
// 圆角矩形
// CGPathAddRoundedRect(path, NULL, CGRectMake(60, 60, 100, 100), 5, 5);
// 弧线
CGPathAddArc (path, NULL , 100 , 100 , 30 , 0 , M_PI , YES );
// 添加路径到上下文中
CGContextAddPath (con, path);
// 显示到 view 中
CGContextStrokePath (con);
}
绘图方式2
#pragma mark - 绘图方式 2
- ( void )draw1 {
// Drawing code
// 获得图形上下文
CGContextRef con = UIGraphicsGetCurrentContext ();
// 绘制路径
// 绘制直线
// CGContextMoveToPoint(con, 0, 0);
// CGContextAddLineToPoint(con, 100, 100);
// CGContextAddLineToPoint(con, 50, 100);
//CGContextMoveToPoint(con, 50, 50);
//
// 绘制圆
// CGContextAddEllipseInRect(con, CGRectMake(60, 60, 100, 100));
// 绘制椭圆
// CGContextAddEllipseInRect(con, CGRectMake(60, 60, 150, 100));
// 绘制矩形
// CGContextAddRect(con, CGRectMake(60, 60, 150, 100));
// 绘制
CGContextAddArc (con, 0 , 0 , 50 , M_PI , M_PI_2 , YES );
// 显示到 view 中
CGContextStrokePath (con);
绘图方式3
#pragma mark - 绘图方式 3- 贝瑟尔路径绘图
// 贝瑟尔路径绘图
- ( void )draw3 {
// Drawing code
// UIKit 已经封装了一些绘图的功能
// 贝瑟尔路径
UIBezierPath *path = [ UIBezierPath bezierPath ];
// 绘制路径
// [path moveToPoint:CGPointMake(100, 100)];
// [path addLineToPoint:CGPointMake(200, 200)];
// 圆弧
[path addArcWithCenter : CGPointMake ( 100 , 100 ) radius : 50 startAngle : 0 endAngle : M_PI clockwise : YES ]; // 顺时针绘制一个弧线
[path addLineToPoint : CGPointMake ( 100 , 100 )];
[[ UIColor redColor ] setStroke ]; // 设置线条颜色
//
path. lineJoinStyle = kCGLineJoinRound ; //
path. lineWidth = 2 ; // 宽度
path. lineCapStyle = kCGLineCapRound ; // 样式
[path fill ];
// 显示
[path stroke ];
}
#pragma mark - 设置线条状态在渲染之前
- ( void )draw4 {
// Drawing code
// 获得图形上下文
CGContextRef ct = UIGraphicsGetCurrentContext ();
// 绘制路径
CGContextMoveToPoint (ct, 100 , 100 );
CGContextAddLineToPoint (ct, 200 , 200 );
CGContextAddLineToPoint (ct, 100 , 300 );
// 设置绘图状态,一定要在渲染之前设置,并且一经设置,状态会一直持续下去,除非再次改变。
CGContextSetLineWidth (ct, 5 );
[[ UIColor redColor ] setStroke ];
CGContextSetLineJoin (ct, kCGLineJoinRound );
CGContextSetLineCap (ct, kCGLineCapRound );
// 渲染
CGContextStrokePath (ct);
}
绘制包含多个状态的图形
- ( void )drawRect:(CGRect)rect {
// Drawing code
// 绘制多个状态不同的线
// 获得图形上下文
UIBezierPath *path = [UIBezierPath bezierPath];
// 绘制路径
[path moveToPoint:CGPointMake( 100 , 100 )];
[path addLineToPoint:CGPointMake( 200 , 200 )];
// 设置绘图状态,一定要在渲染之前设置,并且一经设置,状态会一直持续下去,除非再次改变。
[[UIColor redColor] setStroke];
// 渲染
[path stroke];
// 获得图形上下文
UIBezierPath *path1 = [UIBezierPath bezierPath];
// 绘制路径
[path1 moveToPoint:CGPointMake( 200 , 200 )];
[path1 addLineToPoint:CGPointMake( 100 , 150 )];
// 设置绘图状态,一定要在渲染之前设置,并且一经设置,状态会一直持续下去,除非再次改变。
[[UIColor blueColor] setStroke];
// 渲染
[path1 stroke];
}
首先花圆弧,然后连接圆心,最后填充位一个扇形
// 饼状图 2
- ( void )drawRect:( CGRect )rect{
NSArray *arr = [ self randomArray ]; // 随机地返回一个数组,数组元素和为100
// 获取半径和圆心
CGFloat radius = self . frame . size . height / 2 - 2 ;
CGPoint center = CGPointMake (radius, radius);
// 绘制角度
CGFloat startAngle = 0 ;
CGFloat endAngle = 0 ;
// 绘制图形
for ( int i = 0 ; i < arr. count ; i ++) {
// 计算角度
endAngle = startAngle + [arr[i] floatValue ] / 100.0 * M_PI * 2 ;
// 绘制图形
UIBezierPath *path = [ UIBezierPath bezierPathWithArcCenter :center radius :radius startAngle :startAngle endAngle :endAngle clockwise : YES ];
[path addLineToPoint :center];
startAngle = endAngle;
// 设置颜色
[[ self randomColor ] set ];
// 填充,并且把终点和起始点连接起来
[path fill ];
}
}
随机返回数组,且元素和为100
// 返回随机数组,且数组元素和为 100
- ( NSArray *)randomArray
{
NSMutableArray *arr = [ NSMutableArray array ];
int total = 100 ;
int temp = 0 ;
for ( int i = 0 ; i < arc4random_uniform ( 10 ) + 1 ;i ++) {
// 100 1~100
temp = arc4random_uniform (total) + 1 ;
// 随机出来的临时值等于总值,直接退出循环,因为已经把总数分配完毕,没必要在分配。
[arr addObject : @( temp ) ];
// 解决方式:当随机出来的数等于总数直接退出循环。
if (temp == total) {
break ;
}
total -= temp;
}
// 如果总数大于 0 就添加到数组中
if (total ) {
[arr addObject : @( total ) ];
}
return arr;
}
// 返回随机的颜色
- ( UIColor *)randomColor
{
// iOS : RGB 返回是 0~1
CGFloat r = arc4random_uniform ( 256 ) / 255.0 ;
CGFloat g = arc4random_uniform ( 256 ) / 255.0 ;
CGFloat b = arc4random_uniform ( 256 ) / 255.0 ;
return [ UIColor colorWithRed :r green :g blue :b alpha : 1 ];
}
计算方柱个数,平分宽度,高度按占视图比例计算。
// 柱状图
- ( void )drawRect:( CGRect )rect {
// 随机地返回一个数组,数组元素和为 100
NSArray *arr = [ self randomArray ];
// 起始点和高度
CGFloat x = 0 ;
CGFloat y = 0 ;
CGFloat w = 0 ;
CGFloat h = 0 ;
NSInteger count = arr. count ;
// 宽度
w = rect. size . width / ( 2 *count - 1 );
for ( int i = 0 ; i < arr. count ; i ++) {
// x 坐标
x = 2 *i * w;
// 高度
h = [arr[i] floatValue ] / 100.0 * rect. size . height ;
// y 坐标
y = rect. size . height - h;
UIBezierPath *path = [ UIBezierPath bezierPathWithRect : CGRectMake (x, y, w, h)];
[[ self randomColor ] set ];
[path fill ];
}
}
// 文本显示
- ( void )drawRect:( CGRect )rect
{
NSString *str = @" 哈尽快回家的客户发动机可舒服哈的尽快发货阿红的健康法哈德减肥哈第三方阿姐回复就爱的客户房间卡地方哈就等哈接电话发掘 " ;
// 这个方法不会自动换行
// [str drawAtPoint:CGPointZero withAttributes:nil];
// 自动换行
[str drawInRect :rect withAttributes : nil ];
}
// 富文本:带有状态的文本
- ( void )drawRect:( CGRect )rect
{
NSString *str = @" 哈尽快回家的客户发动机可舒服哈的尽快发货阿红的健康法哈德减肥哈第三方阿姐回复就爱的客户房间卡地方哈就等哈接电话发掘 " ;
NSMutableDictionary *dict = [ NSMutableDictionary dictionary ];
// 属性的设置可以在 UIkit 框架的头文件里找到解释
// 字体颜色
dict[ NSForegroundColorAttributeName ] = [ UIColor redColor ];
// 字体大小
dict[ NSFontAttributeName ] = [ UIFont systemFontOfSize : 30 ];
// 字体粗细
dict[ NSStrokeWidthAttributeName ] = @5 ;
// 颜色
dict[ NSStrokeColorAttributeName ] = [ UIColor greenColor ];
// 阴影
NSShadow *sha = [[ NSShadow alloc ] init ];
sha. shadowOffset = CGSizeMake ( 5 , 5 );
sha. shadowBlurRadius = 10 ;
sha. shadowColor = [ UIColor yellowColor ];
dict[ NSShadowAttributeName ] = sha;
// 绘制到视图
[str drawInRect :rect withAttributes :dict];
}
裁剪
// 绘制图形
- ( void )drawRect:( CGRect )rect
{
// 超出裁剪区域的内容全部裁剪掉
// 注意:裁剪必须放在绘制之前
// UIRectClip(CGRectMake(0, 0, 100, 100));
UIImage *image = [ UIImage imageNamed : @"010" ];
// 默认按照图片比例显示
// [image drawAtPoint:CGPointZero];
// 将整个图片显示到 rect 中,拉伸或者缩小
[image drawInRect :rect];
// 默认填充显示
// [image drawAsPatternInRect:rect];
}
保存某个状态到栈顶,用于之后恢复。
// 图形上下文 3 UIBezierPath: 使用 [path stroke]; 时上下文状态有 UIBezierPath 自身决定
- ( void )drawRect:( CGRect )rect
{
// 保存上下文状态 , 如果使用这种方法保存上下文状态的话,需要设置以 CGContext 开头的那些函数设置状态,
// 获取图形上下文
CGContextRef ctx = UIGraphicsGetCurrentContext ();
// 绘制第一条线
// 贝塞尔路线
UIBezierPath *path = [ UIBezierPath bezierPath ];
// 绘制路径
[path moveToPoint : CGPointMake ( 55 , 55 )];
[path addLineToPoint : CGPointMake ( 99 , 90 )];
// 添加路径到上下文
// 将 c 路径转换成 oc 对象: CGPath
CGContextAddPath (ctx, path. CGPath );
// 保存上下文状态
CGContextSaveGState (ctx);
CGContextSetLineWidth (ctx, 5 );
[[ UIColor redColor ] setStroke ];
// 渲染上下文
// [path stroke];
CGContextStrokePath (ctx);
// 绘制第二条线
path = [ UIBezierPath bezierPath ];
// 绘制路径
[path moveToPoint : CGPointMake ( 100 , 10 )];
[path addLineToPoint : CGPointMake ( 100 , 80 )];
// 恢复上下文状态
CGContextRestoreGState (ctx);
// 添加路径到上下文
CGContextAddPath (ctx, path. CGPath );
// [[UIColor blueColor] setStroke];
// 渲染
// [path stroke];
CGContextStrokePath (ctx);
}
如果在绘图的时候需要用到定时器,通常 CADisplayLink
NSTimer 很少用于绘图,因为调度优先级比较低,并不会准时调用
// 如果在绘图的时候需要用到定时器,通常 CADisplayLink
// NSTimer 很少用于绘图,因为调度优先级比较低,并不会准时调用
- ( void )awakeFromNib
{
// 添加计时器,改变 _smailY 的值
// 比起 NSTimer , CADisplayLink 可以确保系统渲染每一帧的时候我们的方法都被调用,从而保证了动画的流畅性。
// CADisplayLink: 每次屏幕刷新的时候就会调用,屏幕一般一秒刷新 60 次
CADisplayLink *link = [ CADisplayLink displayLinkWithTarget : self selector : @selector (timeChange)];
// 添加至运行主循环
[link addToRunLoop :[ NSRunLoop mainRunLoop ] forMode : NSDefaultRunLoopMode ];
}
- ( void )timeChange
{
// 注意:这个方法并不会马上调用 drawRect, 其实这个方法只是给当前控件添加刷新的标记,等下一次屏幕刷新的时候才会调用 drawRect
[ self setNeedsDisplay ];
}
// 上下文矩阵操作
// 注意 : 矩阵操作必须要在添加路径之前
-( void )drawRect:( CGRect )rect
{
// 获取图形山下文
CGContextRef ctx1 = UIGraphicsGetCurrentContext ();
// CGContextSaveGState(ctx1);
// 绘制路径 1
// CGContextMoveToPoint(ctx1, 50, 50);
CGContextTranslateCTM (ctx1, 100 , 0 ); // 添加路径之前进行矩阵操作
CGContextScaleCTM (ctx1, 2 , 2 );
CGContextRotateCTM (ctx1, M_PI_2 );
CGContextAddEllipseInRect (ctx1, CGRectMake ( 10 , 10 , 50 , 90 ));
[[ UIColor redColor ] setStroke ];
CGContextSetLineWidth (ctx1, 5 );
CGContextSetLineJoin (ctx1, kCGLineJoinRound );
// 渲染路径
CGContextStrokePath (ctx1);
}