quartz c语言,quartz2D 的从零到一学习使用(附赠源码)

2024-01-31 19:40

本文主要是介绍quartz c语言,quartz2D 的从零到一学习使用(附赠源码),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

f9f05e12ddd3

demo中有苹果婊

什么是Quartz2D?二维的绘图引擎

什么是二维?平面

什么是引擎?经包装的函数库,方便开发者使用。也就是说苹果帮我们封装了一套绘图的函数库

同时支持iOS和Mac系统什么意思?用Quartz2D写的同一份代码,既可以运行在iphone上又可以运行在mac上,可以跨平台开发。

开发中比较常用的是截屏/裁剪/自定义UI控件。

Quartz2D在iOS开发中的价值就是自定义UI控件。

使用图形上下文画图,要遵循一下四个步骤

1.获取图像上下文

2.创建路径

3.将路径添加到图形上下文(add)

4.渲染图像上下文(fill,stroke)

一.绘制一条直线的方法

1.直接使用图形上下文画图

//只有在drawRect方法中才能拿到图形上下文,才可以画图

- (void)drawRect:(CGRect)rect {

//1.获取图形上下文,目前我们现在使用的都是UIGraphics开头,CoreGraphics,项目的简称CG

CGContextRef ctx = UIGraphicsGetCurrentContext();

//2.描述路径

//2.1 创建路径

CGContextMoveToPoint(ctx, 14, 19);

//2.2 添加线到一个点

CGContextAddLineToPoint(ctx, 45, 65);

//3.完成路线

CGContextStrokePath(ctx);

}

2.使用图形上下文+CGPathRef画线

- (void)drawRect:(CGRect)rect {

//1.获取图形上下文,目前我们现在使用的都是UIGraphics开头,CoreGraphics,项目的简称CG

CGContextRef ctx = UIGraphicsGetCurrentContext();

//2.使用path来画线

CGMutablePathRef path = CGPathCreateMutable();

//3.添加点

CGPathMoveToPoint(path, NULL, 34, 23);

CGPathAddLineToPoint(path, NULL, 56, 43);

//4.将path添加到图像上下文上

CGContextAddPath(ctx, path);

//5.渲染上下文

CGContextStrokePath(ctx);

}

3.贝塞尔曲线

实际上方法都是一样的,只是添加没有获取图形上下文,在底层,系统已经给封装了

- (void)drawRect:(CGRect)rect {

//1.创建路径

UIBezierPath *path = [UIBezierPath bezierPath];

//2.画线

[path moveToPoint:CGPointMake(23, 45)];

[path addLineToPoint:CGPointMake(66, 88)];

//3.渲染

[path stroke];

}

4.图形上下文+贝塞尔曲线

- (void)drawRect:(CGRect)rect {

//使用贝塞尔曲线和图形上下文画图

CGContextRef ctx = UIGraphicsGetCurrentContext();

UIBezierPath *path = [UIBezierPath bezierPath];

[path moveToPoint:CGPointZero];

[path addLineToPoint:CGPointMake(233, 69)];

//这个是C语言的写法,必须使用path.CGPath,否则无效

CGContextAddPath(ctx, path.CGPath);

CGContextStrokePath(ctx);

}

1.用四种方法,说明绘制图形有很多种方法

2.底层的是2.CGMutablePathRef,绘制图形实际上就是一直设置path

3.CGContextMoveToPoint(实际上底层已经给我们分装了CGPat,但只有一个)c语言的方法,UIBezierPath抽象出的面向对象的类

4.不管哪种,思路都是一样的

5.个人推荐的是使用1,2,3,不推荐4,两个东西杂糅,不太喜欢

二.画两个链接的线,并且设置属性

f9f05e12ddd3

两条相交的线

//只有在drawRect方法中才能拿到图形上下文,才可以画图

- (void)drawRect:(CGRect)rect {

//1.获取图形上文

CGContextRef ctx = UIGraphicsGetCurrentContext();

//2.将绘制路径,并且将其添加到图形上下文

CGContextMoveToPoint(ctx,123, 45);

CGContextAddLineToPoint(ctx, 45, 80);

//添加另一根线

CGContextAddLineToPoint(ctx, 223, 159);

//设置颜色

[[UIColor greenColor] set];

//设置线的宽度

CGContextSetLineWidth(ctx, 10);

//设置链接处的链接类型

CGContextSetLineJoin(ctx, kCGLineJoinMiter);

//设置线的头部样式

CGContextSetLineCap(ctx, kCGLineCapButt);

//渲染

CGContextStrokePath(ctx);

}

画出了两条有链接的线,其中设置颜色的时候,是区分设置线的颜色,和设置图片的颜色的,可以设置他们各自的属性(但是经常设置错误),懒得去区分并且保证不会设置错误,建议设置[[UIColor greenColor] set]就不用考虑实线还是填充图形了。还有,CGContextSetLineJoin是设置连接处的样式,是枚举,CGContextSetLineCap是设置线的顶部的样式,也是枚举。

注意:设置各种属性的时候,一定要记住在渲染之前,否则无效

三.绘制两条不相交的线,并且设置各自属性

f9f05e12ddd3

两条不相交的线,设置他们的属性

- (void)drawRect:(CGRect)rect {

UIBezierPath *path = [UIBezierPath bezierPath];

[path moveToPoint:CGPointMake(12, 49)];

[path addLineToPoint:CGPointMake(68, 34)];

[path setLineWidth:3];

[[UIColor redColor] set];

[path stroke];

//设置第2个线段

UIBezierPath *path2 = [UIBezierPath bezierPath];

[path2 moveToPoint:CGPointMake(145, 167)];

[path2 addLineToPoint:CGPointMake(98, 34)];

[path2 setLineWidth:10];

[[UIColor greenColor] set];

[path2 setLineCapStyle:kCGLineCapRound];

[path2 stroke];

}

使用贝塞尔曲线画图的好处在于,1.每一个贝塞尔底层都有一个图形上线文,如果是用CGContextMoveToPoint画图,实际上就是一个图形上下文,不好去控制,所以建议没多条线可以使用贝塞尔曲线或者说使用底层的CGMutablePathRef画线,比较靠谱

四.绘制曲线

f9f05e12ddd3

曲线

- (void)drawRect:(CGRect)rect {

//绘制一条曲线

CGContextRef ctx = UIGraphicsGetCurrentContext();

//设置起点

CGContextMoveToPoint(ctx, 10, 10);

/**

* 添加曲线的五个参数

*

* @param c#> 图形上下文

* @param cpx#> 将来要突出的x值

* @param cpy#> 要突出的y值

* @param x#> 曲线结束时的x

* @param y#> 曲线结束时的y

*/

CGContextAddQuadCurveToPoint(ctx, 50, 50, 100, 10);

//设置颜色

[[UIColor redColor] set];

//渲染图层

CGContextStrokePath(ctx);

}

五.绘制带有圆角边框的正方形

f9f05e12ddd3

圆角的矩形们

- (void)drawRect:(CGRect)rect {

//绘制一个圆角矩形

UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(10, 10, 100, 40) cornerRadius:5];

[[UIColor orangeColor] set];

[path stroke];

//绘制一个圆角矩形

UIBezierPath *path2 = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(10, 110, 100, 40) cornerRadius:5];

[[UIColor greenColor] set];

[path2 fill];

//绘制一个原形(不规范的绘制)

UIBezierPath *path3 = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(140, 10, 100, 100) cornerRadius:50];

[[UIColor cyanColor] set];

[path3 fill];

}

1.stroke设置边框的颜色,fill填充内部的颜色

2.fill并不是随意使用的,必须是封闭的图形。

3.可以通过设置圆角是正方形的高度,生成一个原形,但不是最规范绘制原形的方法,不过也可以使用。

六.绘制一个弧度曲线

f9f05e12ddd3

弧度曲线

- (void)drawRect:(CGRect)rect {

/**

* 绘制弧度曲线

*

* @param ArcCenter 曲线中心

* @param radius 半径

* @param startAngle 开始的弧度

* @param endAngle 接收的弧度

* @param clockwise YES顺时针,NO逆时针

*/

UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(100, 100) radius:14 startAngle:0 endAngle:M_PI clockwise:YES];

[[UIColor greenColor] set];

[path stroke];

//结束角度如果是M_PI *2 就是一个圆

UIBezierPath *path1 = [UIBezierPath bezierPathWithArcCenter:CGPointMake(240, 140) radius:40 startAngle:0 endAngle:M_PI * 2 clockwise:YES];

[[UIColor purpleColor] set];

[path1 fill];

//绘制115度角的圆弧

UIBezierPath *path2 = [UIBezierPath bezierPathWithArcCenter:CGPointMake(200, 100) radius:20 startAngle:0 endAngle:115/360.0*(M_PI *2) clockwise:NO];

[[UIColor orangeColor] set];

[path2 stroke];

}

1.M_PI是180度.M_PI_2是90°

2.这里的角度都是弧度制度,如果我们需要15°,可以用15°/180°*π得到。

3.clockwise这个是顺时针,如果穿1,就是顺时针,穿0,是逆时针

七.绘制一个一个扇形

f9f05e12ddd3

扇形

- (void)drawRect:(CGRect)rect {

//1.获取图形上下文

CGContextRef ctx = UIGraphicsGetCurrentContext();

//绘制曲线

CGFloat centerX = 100;

CGFloat centerY = 100;

CGFloat radius = 30;

//添加一根线·

CGContextMoveToPoint(ctx, centerX, centerY);

CGContextAddArc(ctx, centerX, centerY, radius, M_PI, M_PI_2, NO);

//关闭线段

CGContextClosePath(ctx);

//渲染

CGContextStrokePath(ctx);

}

1.线添加一个点CGContextMoveToPoint

2.添加一个圆弧CGContextAddArc

3.闭合绘图CGContextClosePath

4.给路径设置颜色CGContextStrokePath,或者给图形内部设置颜色CGContextFillPath

5.使用贝塞尔曲线,也要设置闭合路径CGContextClosePath

八.简单下载进度的demo

f9f05e12ddd3

demo下载进度

- (void)setProgressValue:(CGFloat)progressValue{

_progressValue = progressValue;

[self setNeedsDisplay];

}

- (void)drawRect:(CGRect)rect {

CGFloat radius = self.frame.size.height * 0.5 - 10;

CGFloat endA = self.progressValue*M_PI*2 - M_PI_2;

UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(radius+5,radius+5) radius:radius-5 startAngle:-M_PI_2 endAngle:endA clockwise:YES];

path.lineWidth = 10;

path.lineCapStyle = kCGLineCapRound;

[[UIColor redColor] set];

[path stroke];

}

demo上传github,DEMO链接,上边是重要的代码

2.在UIBezierPath的bezierPathWithArcCenter:radius:startAngle:endAngle:clockwise:中clockwise: == 1表示顺时针

3.CGContextAddArc(ctx, centerX, centerY, radius, M_PI, M_PI_2, NO),clockwise == 0表示顺时针

4.想调用这个方法drawRect:(CGRect)rect,必须要使用setNeedsDisplay,其他的无效。

九.饼状图

f9f05e12ddd3

饼状图

@interface WXView ()

@property(nonatomic,strong)NSArray *nums;

@property(assign,nonatomic)NSInteger total;

@end

@implementation WXView

-(NSInteger )total{

if (_total == 0) {

for (int j = 0; j < self.nums.count; j++) {

_total += [self.nums[j] integerValue];

}

}

return _total;

}

-(NSArray *)nums{

if (!_nums) {

_nums = @[@23,@34,@33,@13,@30,@44,@66];

}

return _nums;

}

//只有在drawRect方法中才能拿到图形上下文,才可以画图

- (void)drawRect:(CGRect)rect {

//绘制一个饼状图

CGFloat centX = 100;

CGFloat centY = 100;

CGPoint center = CGPointMake(centX, centY);

CGFloat radius = 50;

CGFloat startA = 0;

CGFloat endA = 0;

for (int i = 0; i < self.nums.count; i++) {

NSNumber *data = self.nums[i];

startA = endA;

endA = startA + [data floatValue]/self.total * 2 * M_PI;

UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:YES];

[path addLineToPoint:center];

CGFloat randRed = arc4random_uniform(256)/255.0;

CGFloat randGreen = arc4random_uniform(256)/255.0;

CGFloat randBlue = arc4random_uniform(256)/255.0;

UIColor *randomColor = [UIColor colorWithRed:randRed green:randGreen blue:randBlue alpha:1.0];

[randomColor set];

[path fill];

}

}

十.柱状图

f9f05e12ddd3

柱状图

-(NSArray *)nums{

if (!_nums) {

_nums = @[@23,@34,@93,@2,@55,@46];

}

return _nums;

}

//只有在drawRect方法中才能拿到图形上下文,才可以画图

- (void)drawRect:(CGRect)rect {

//1.获取图形上下文

CGContextRef ctx = UIGraphicsGetCurrentContext();

//2.绘制图像

CGFloat margin = 30;

CGFloat width = (rect.size.width - (self.nums.count + 1)*margin)/self.nums.count;

for (int i = 0; i < self.nums.count; i++) {

CGFloat x = margin + (width + margin)*i;

CGFloat num = [self.nums[i] floatValue]/100;

CGFloat y = rect.size.height * (1-num);

CGFloat height = rect.size.height*num;

CGRect rectA = CGRectMake(x, y, width, height);

CGContextAddRect(ctx,rectA);

[[self randomColor] set];

CGContextFillPath(ctx);

}

}

十一.绘制图片

绘制文字和图片的时候,是不用去获取图像上下文的

f9f05e12ddd3

平铺

f9f05e12ddd3

固定位置画图

f9f05e12ddd3

默认固定大小

- (void)drawRect:(CGRect)rect {

//剪切图片,超出的图片位置都要剪切掉!必须要在绘制之前写,否则无效

// UIRectClip(CGRectMake(0, 0, 100, 50));

UIImage *image = [UIImage imageNamed:@"1"];

//(渲染)默认绘制的大小就是图片的大小,也可以自己设置一下

//在什么范围下(原图大小)

[image drawInRect:rect];

//在哪个位置开始画

[image drawAtPoint:CGPointMake(10, 10)];

//平铺

[image drawAsPatternInRect:rect];

}

十二.绘制富文本

f9f05e12ddd3

苹果富文本

- (void)drawRect:(CGRect)rect {

NSString *str = @"每个人都\n应该喜欢敲代\n码,只有这样,\n科技才能改变生活";

//设置文字的属性

NSMutableDictionary * paras = [NSMutableDictionary dictionary];

paras[NSFontAttributeName] = [UIFont systemFontOfSize:40];

paras[NSForegroundColorAttributeName] = [UIColor redColor];

paras[NSStrokeColorAttributeName] = [UIColor orangeColor];

paras[NSStrokeWidthAttributeName] = @3;

//创建阴影对象

NSShadow *shodow = [[NSShadow alloc] init];

shodow.shadowColor = [UIColor blueColor];

shodow.shadowOffset = CGSizeMake(5, 6);

shodow.shadowBlurRadius = 4;

//苹果的富文本就是这样搞出来的

paras[NSShadowAttributeName] = shodow;

[str drawAtPoint:CGPointZero withAttributes:paras];

}

十三.自定义一个ImageView

f9f05e12ddd3

WXImageView继承自UIView

WXImageView.h文件中定义的属性和接口和UIImageView一样,继承自UIView

- (id)initWithImage:(UIImage *)image;

@property(nonatomic,strong)UIImage *image;

WXImageView.m中方法的具体实现

- (id)initWithImage:(UIImage *)image{

if (self = [super initWithFrame:CGRectMake(0, 0, image.size.width, image.size.height)]) {

_image = image;

}

return self;

}

- (void)setImage:(UIImage *)image{

_image = image;

[self setNeedsDisplay];

}

- (void)drawRect:(CGRect)rect {

[self.image drawInRect:rect];

}

在vc中调用

WXImageView *imageV = [[WXImageView alloc] initWithImage:[UIImage imageNamed:@"1"]];

imageV.center = CGPointMake(100, 50);

[self.view addSubview:imageV];

即使在xib使用,我发现和UIImageView的结果都是一样的

十四.雪花飘动

f9f05e12ddd3

雪花动画

//只有在drawRect方法中才能拿到图形上下文,才可以画图

- (void)drawRect:(CGRect)rect {

//设置下雪的动画

UIImage *image = [UIImage imageNamed:@"snow"];

_snowY += 10;

[image drawAtPoint:CGPointMake(0, _snowY)];

if (_snowY >= rect.size.height) {

_snowY = 0;

}

}

// 如果在绘图的时候需要用到定时器,通常使用CADisplayLink

// NSTimer很少用于绘图,因为调度优先级比较低,并不会准时调用

- (void)awakeFromNib

{

// 创建定时器

CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(timeChange)];

// 添加主运行循环

[link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];

}

// CADisplayLink:每次屏幕刷新的时候就会调用,屏幕一般一秒刷新60次

- (void)timeChange{

[self setNeedsDisplay];

}

1.本质就是调用drawRect方法,一直刷新雪花的y值

2.每一次调用drawRect,都创建大量的对象,有人说可能性能不好,不过你可能多虑了,没吃都是在内存加载,不会创建新的UIImage

十五.图形上下文栈

我自己详细的介绍了一下,上下文栈,可以看一下~

图形上下文详解

十六.图形上下文矩阵

到底是个啥?

就是图形上下文画出的东西永远是方方正正的,你要是想画个偏离的矩形,按照过去的方法画不出来,只能使用矩阵的方式。分别有偏移,缩放,旋转

f9f05e12ddd3

正常尺寸的椭圆

f9f05e12ddd3

x,y各自平移10px后的椭圆

f9f05e12ddd3

旋转后的椭圆

f9f05e12ddd3

缩放后的椭圆

- (void)drawRect:(CGRect)rect {

//图形上下文矩阵

//1.画一个椭圆

CGContextRef ctx = UIGraphicsGetCurrentContext();

// CGContextAddEllipseInRect(ctx, CGRectMake(100, 100, 100, 100));

CGPathRef path = CGPathCreateWithEllipseInRect(CGRectMake(0, 0, 200, 100),nil);

[[UIColor redColor] set];

//1.偏移

// CGContextTranslateCTM(ctx, 10, 10);

//2.旋转

// CGContextRotateCTM(ctx, M_PI_4);

//3.缩放

CGContextScaleCTM(ctx, 0.25, 2);

CGContextAddPath(ctx, path);

CGContextFillPath(ctx);

}

1.绘制变化的图形的步骤

先绘制path

设置图形上下文矩阵

将path添加到图形上下文(这一步很重要,一定按照步骤来)

渲染

2.绘图的时候,我们要使用底层的** CGPathRef,或者贝塞尔,然后 CGContextRef+path的方式。

如不这样,我注释的CGContextAddEllipseInRect(ctx, CGRectMake(100, 100, 100, 100))方法,这个方法中已经先去添加了path到图形上下文,即使我们在去添加图形上下文矩阵,也是无效

3.可以和图形上下文栈**一起使用,给特定的一些图案设置一些属性,还有一些不会受到影响

本文特别感谢小马哥教育,参考了他们的视频,做的一个总结。文章的demo已经更新到了github,如有需要,可以参考

这篇关于quartz c语言,quartz2D 的从零到一学习使用(附赠源码)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/664858

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听