iOS学习——Quartz2D学习之UIKit绘制
iOS学习——Quartz2D学习之UIKit绘制
1、总述
在IOS中绘图技术主要包括:UIKit、Quartz 2D、Core Animation和OpenGL ES。其中Core Animation提供动画实现技术,OpenGL ES是OpenGL针对嵌入式设备的简化版本,用以绘制高性能的2D和3D图形。这里主要UIKit和Quartz 2D。
- UIKit。它是高级别的图形接口,它的API都是基于Objective-C的。它能够访问绘图、动画、字体、图片等内容。
- Quartz 2D。是IOS和Mac OS X环境下的2D绘图引擎。涉及内容包括:基于路径的绘图,透明度绘图,遮盖,阴影,透明层,颜色管理,防锯齿渲染,生成PDF,以及PDF元数据相关处理。Quartz 2D也被称为Core Graphics,缩写前缀为CG。Quartz 2D与Quartz Compositor统称为Quartz,Quartz原本是Mac OS X的Darwin核心之上的绘图技术。它的API接口都是基于C的。
在IOS上无论采用哪种绘图技术(UIKit、Quartz 2D、Core Animation和OpenGL ES),都离不开UIView,绘制都发生在UIView对象的区域内。在绘制发生的时候如果使用的是系统提供的视图,绘制工作会自动得到处理。然而,如果是自定义视图,则必须重写drawRect:方法,在此提供相应的绘制代码。一旦drawRect:方法被调用,就可以使用任何的UIKit、Quartz 2D、OpenGL ES等技术对视图的内容进行绘制了。
绘图过程中除了使用了drawRect:方法,还有setNeedsDisplay和setNeedsDisplayInRect:。setNeedsDisplay和setNeedsDisplayInRect:方法是设置视图或者视图部分区域是否需要重新绘制,setNeedsDisplay是重新绘制整个视图,setNeedsDisplayInRect是重新绘制视图的部分区域。原则上,尽量不要绘制视图的全部,以减少绘制带来开销。触发视图重新绘制的动作有如下几种:
- 当遮挡你的视图的其他视图被移动或删除操作的时候;
- 将视图的hidden属性声明设置为NO,使其从隐藏状态变为可见;
- 将视图滚出屏幕,然后再重新回到屏幕上;
- 显式调用视图的setNeedsDisplay或者setNeedsDisplayInRect:方法
2、UIKit的基本绘图功能
UIKit提供非常基本的绘图功能,主要的API有:
- UIRectFill(CGRect rect),填充矩形函数
- UIRectFrame(CGRect rect),矩形描边函数
- UIBezierPath,绘制常见路径类,包括险段、渐变、阴影、反锯齿等高级特性支持还是不及Quartz 2D。
3、文本绘制
- 先创建好要画的文字
- 使用UIKit提供的方法进行绘制,drawAtPoint:要画到哪个位置 withAttributes:文本的样式.
[str drawAtPoint:CGPointZero withAttributes:nil];
- 前面说了,所有的绘制工作都应该放到drawRect:中进行,所以上面两步的代码不应该放在init、initWithFrame:或者AwakeFromNib方法中,在这些方法中这样写是画不出文字的。因为想要把一个东西画到View上面,必须获得该view的上下文 ,上下文只有在DrawRect方法中才能拿到。
4、drawAtPoint: withAttributes:的底层实现是怎样的?
drawAtPoint: withAttributes:底层也是同样也是按以下着步骤来的:
- 第一步:获取上下文
- 第二步:拼接路径
- 第三步:把路径添加到上下文
- 第四步:渲染上下文到View
所以,不管有没有上下文,只要在View上面画东西,都得要在DrawRect方法中去写
5、如何添加绘制文字属性?
通过绘制方法的最后一个属性withAttributes来设置文字属性,它要求传入的是一个字典.它是通过字典的key和Value的形式来设置文字样式.。那传什么key,什么值我们可以在UIKit头文件当中的NSAttributedString类当中去找。使用形式如下:
- (void)drawRect:(CGRect)rect { NSString *str = @"打印信息 打印信息"; NSMutableDictionary *dict = [NSMutableDictionary dictionary];
//字体
dict[NSFontAttributeName] = [UIFont systemFontOfSize:];
//颜色
dict[NSForegroundColorAttributeName] = [UIColor redColor];
//设置边框颜色
dict[NSStrokeColorAttributeName] = [UIColor redColor];
dict[NSStrokeWidthAttributeName] = @; NSShadow *shadow = [[NSShadow alloc] init];
shadow.shadowOffset = CGSizeMake(, );
shadow.shadowColor = [UIColor greenColor];
shadow.shadowBlurRadius = ;
dict[NSShadowAttributeName] = shadow;
//Attributes:给文字添加一些属性,富文本
[str drawAtPoint:CGPointZero withAttributes:dict];
}
6、drawAtPoint:和drawInRect:的区别?
- drawAtPoint:不能够自动换行
- drawInRect:能够自动换行
7、如何利用UIKit绘制一张图片?
在前面我们学会了如何在自定义view中绘制文本信息,其实绘制图片的方法绘制文本的方法非常类似,所以基本步骤如下:
- 导入素材
- 在DrawRect加载图片 UIImage *image = [UIImage imageNamed:@"image001"];
- 绘制图片: [image drawAtPoint:CGPointZero];
8、绘制图片有哪些方法,区别是什么?
绘制图片的方法有三种,其区别分别如下:
- drawAtPoint:(CGPoint *)point:从指定的点为图片的左上角的起点开始绘制,绘制出来的图形跟图片尺寸一样大,图片是按照原始大小进行绘制,吐过图片的大小超出当前view的视图范围,则无法进行绘制。
- drawInRect:(CGRect *)rect:在指定的rect区域内绘制整张图片,图片会按照指定区域的宽高进行缩放,所以这种方式一定可以显示完整的图片,但是会进行一些缩放。
- drawAsPatternInRect:(CGRect *)rect:在指定的rect区域内平铺图片,如果一张图片不够用,则会在剩下的地方重新放置该图片,图片的大小尺寸不会改变。
9、如何选用UIKit提供的方法快速画一个矩形?
UIRectFill(rect);快速的用矩形去填充一个区域
UIRectFrame(rect);快速绘制一个矩形的边框
10、用UIKit裁剪一个区域
- UIRectClip(CGRectMake(0, 0, 50, 50));只要超出裁剪区域部分,都会被裁剪掉
- 这个方法必须要设置好裁剪区域,才能有裁剪
- 把它放到最后面,没有裁剪效果
//会填充整个rect的区域,指定的裁剪不会有效
UIRectClip(CGRectMake(, , , ));
UIRectFill(rect); //只会填充指定的裁剪区域,其他部分不会填充
UIRectFill(rect);
UIRectClip(CGRectMake(, , , ));
11、图形上下文状态栈?
- 上下文状态栈为内存中的一块区域,它用来保存前上下文当的状态。
- 我们获取的图层上下文当中其实两块区域,一个是存放添加的路径,一个是用来保存用户设置的状态,这些状态包括线条的颜色,线宽等。
- 当我们把上下文的内容渲染到View上面的时候,它会自动将设置的所有上下文状态运行到保存的路径上面显示到View上面。
- 如果想要有多种状态,可以先把路径渲染到View上面,再重新添加路径,添加完路径之后,重新设置上下文的状态,再把新设置的上下文状态渲染到View上面。
- 我们可以利用上下文状态栈的方式,在设置状态之前,把之前的状态保存到上下文状态栈里面。下一次想要再使用之前的状态时,可以从上下文状态当中取出之前保存的上下文状态。
12、如何保存到上下文状态栈,又如何从上下文状态栈中取出状态?
- 如何把上下文状态保存到上下文状态栈? CGContextSaveGState(ctx);
- 如何从上下文状态栈中取出上下文状态? CGContextRestoreGState(ctx);
13、上下文的矩阵操作
上下文的矩阵操作其实就是修改上下文的形变,主要有以下几种:
- 平移 CGContextTranslateCTM(ctx, 100, 100);
- 旋转 CGContextRotateCTM(ctx, M_2_PI);
- 缩放 CGContextScaleCTM(ctx, 0.5, 0.5);
- 注意:上下文操作必须得要在添加路径之前去设置
- (void)drawRect:(CGRect)rect {
//1.获得跟View相关联的上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
//2.描述路径
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(-, -, , )];
[[UIColor redColor] set];
//上下文的矩阵操作,必须得要在添加路径之前做操作.
//平移
CGContextTranslateCTM(ctx, , );
//缩放
CGContextScaleCTM(ctx, 0.5, 0.5);
//旋转
CGContextRotateCTM(ctx, M_PI_4);
//3.把路径 添加到当前上下文
CGContextAddPath(ctx, path.CGPath);
//4.把上下文的内容渲染出来.
CGContextFillPath(ctx); }
14、如何给图片加水印?
添加水印它最终是生成了一个新的图片。之前一直在自定义View,是因为要拿跟View相关联的上下文,跟View相关联的上下文是系统自动帮我们创建的,所以不需要我们自己手动创建。但是生成图片要用到图片上下文,图片上下文需要我们自己去手动创建,还需要我们自己手动去关闭,所以不需要再去自定义View。
实现水印效果的思路:
- 开启一个和原始图片一样的图片上下文.
- 把原始图片先绘制到图片上下文.
- 再把要添加的水印(文字,logo)等绘制到图片上下文.
- 最后从上下文中取出一张图片.
- 关闭图片上下文.
1.如何开启一个图片上下文?
UIGraphicsBeginImageContextWithOptions(image.size, YES, 0);
size:开启多大的上文
opaque:不透明度
scale:缩放上下文.
2.如何从图片上下文当中生成一张图片?
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
3.如何关闭上下文?
UIGraphicsEndImageContext();
- (void)viewDidLoad {
[super viewDidLoad];
//生成图片.
UIImage *image = [UIImage imageNamed:@"image001"];
//size:开开启一个多大图片上下文.
//opaque:不透度
//scale:0
//开启跟图片相同的大小上下文.
UIGraphicsBeginImageContextWithOptions(image.size, NO, 0.0);
//把图片给绘制图片上下文.
[image drawAtPoint:CGPointZero];
//绘制水印 文字或图片都 ok
NSString *str = @"小码哥";
[str drawAtPoint:CGPointZero withAttributes:@{NSFontAttributeName : [UIFont systemFontOfSize:]}];
//生成图片
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
//手动关闭上下文
UIGraphicsEndImageContext();
//显示添加水印后的新图片
self.imageV.image = newImage;
}
15、如何进行图片裁剪?
对图片进行裁剪的流程如下: 先添加裁剪去,再进行绘制
- 开启一个图片上下文.
- 上下文的大小和原始图片保持一样,以免图片被拉伸缩放.
- 在上下文的上面添加一个圆形裁剪区域,圆形裁剪区域的半径大小和图片的宽度一样大.
- 把要裁剪的图片绘制到图片上下文当中.
- 从上下文当中取出图片.
- 关闭上下文.
- (void)viewDidLoad {
[super viewDidLoad];
//1.加载图片
UIImage *image = [UIImage imageNamed:@"阿狸头像"];
//2.生成一个跟图片相同大小图片上下文
UIGraphicsBeginImageContextWithOptions(image.size, NO, );
//3.在上下文添加一个圆形裁剪区域
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(, , image.size.width, image.size.height)];
//把路径设置成裁剪区域
[path addClip]; //可以加一个图形上下文的操作 旋转
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextRotateCTM(ctx, M_PI_4);
CGContextAddPath(ctx, path.CGPath); //4.把图片绘制图片上下文.
[image drawAtPoint:CGPointZero];
//5.生成一张图片
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
//6.关闭图片上下文.
UIGraphicsEndImageContext();
self.imageV.image = newImage;
}
16、如何进行截屏操作?
截屏效果实现具体思路为:把UIView的东西绘制图片上下文当中,生成一张新的图片。
注意:UIView上的东西是不能直接画到上下文当中的.
UIView之所以能够显示是因为内部的一个层(layer),所以我要把层上的东西渲染到UIView上面的,那么怎样把图层当中的内容渲染到上下文当中?直接调用layer的renderInContext:方法
renderInContext:带有一个参数, 就是要把图层上的内容渲染到哪个上下文。
截屏具体实现代码为:
- 开启一个图片上下文 UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, 0);
- 获取当前的上下文 CGContextRef ctx = UIGraphicsGetCurrentContext();
- 把控制器View的内容绘制上下文当中 [self.view.layer renderInContext:ctx];
- 从上下文当中取出图片 UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
- 关闭上下文 UIGraphicsEndImageContext();
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
//1.开启图片上下文.
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, );
//获取当前的上下文.
CGContextRef ctx = UIGraphicsGetCurrentContext();
//UIView之所能够显示,是因为它内部有一个层,layer.层是通过渲染的方法,给绘制上下文.
[self.view.layer renderInContext:ctx];
//生成一张图片.
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
//如何把图片转换成二进流.
NSData *data = UIImagePNGRepresentation(newImage);
[data writeToFile:@"/Users/gaoxinqiang/Desktop/newImage.png" atomically:YES];
//关闭上下文.
UIGraphicsEndImageContext();
}
iOS学习——Quartz2D学习之UIKit绘制的更多相关文章
- iOS学习——Quartz2D学习之DrawRect
Quartz2D学习之DrawRect 本文以问答形式主要讲述Quartz2D的相关内容,参考内容是网上下载的学习视频资料. 1.什么是Quartz2D? 他是一个二维的绘图引擎,同时支持iOS和Ma ...
- iOS:quartz2D绘图(显示绘制在PDF上的图片)
quart2D既可以用来绘制图像到pdf上,也可以从pdf上读取图像并显示出来.在使用这种方式之前,还有一种方式可以用来读取显示pdf上的图像,即使用UIWebView网页视图控件- (void)lo ...
- 移动开发iOS&Android对比学习--异步处理
在移动开发里很多时候需要用到异步处理.Android的主线程如果等待超过一定时间的时候直接出现ANR(对不熟悉Android的朋友这里需要解释一下什么叫ANR.ANR就是Application Not ...
- 关于iOS开发的学习
关于iOS开发的学习,打个比方就像把汽车分解: 最底层的原料有塑料,钢铁 再用这些底层的东西造出来发动机,座椅 最后再加上写螺丝,胶水等,把汽车就拼起来了 iOS基本都是英文的资料, ...
- iOS开发如何学习前端(2)
iOS开发如何学习前端(2) 上一篇成果如下. 实现的效果如下. 实现了一个横放的<ul>,也既iOS中的UITableView. 实现了当鼠标移动到列表中的某一个<li>,也 ...
- iOS开发如何学习前端(1)
iOS开发如何学习前端(1) 我为何学前端?因为无聊. 概念 前端大概三大块. HTML CSS JavaScript 基本上每个概念在iOS中都有对应的.HTML请想象成只能拉Autolayout或 ...
- ios开发网络学习AFN框架的使用一:get和post请求
#import "ViewController.h" #import "AFNetworking.h" @interface ViewController () ...
- iOS开发 - Quartz2D画图
Quartz 2D简单介绍 是一个二维画图引擎,同一时候支持iOS和Mac系统 Quartz 2D能完毕的工作 绘制图形 : 线条\三角形\矩形\圆\弧等 绘制文字 绘制\生成图片(图像) 读取\生成 ...
- IT人的自我导向型学习:学习的4个层次
谈起软件开发一定会想到用什么技术.采用什么框架,然而在盛行的敏捷之下,人的问题逐渐凸显出来.不少企业请人来培训敏捷开发技术,却发现并不能真正运用起来,其中一个主要原因就是大家还没有很好的学习能力.没有 ...
随机推荐
- C++ 面向对象的三大特性和五个原则
1.三大特性: 封装:就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏.一个类就是一个封装了数据以及操作这些数据的代码的逻辑实体.在一个对象内 ...
- HDU - 6054 sa + 树状数组套线段树
因为强制在线所以只能转成序列上的问题然后树套树了... #include<bits/stdc++.h> #define LL long long #define LD long doubl ...
- Python制作微信小助手
网址: https://mp.weixin.qq.com/s/uWSgeD5FyzXV3LsMNus01Q
- Vagrant 安装以及private_network配置
(需先安装virtuabox,vagrant) 1.下载centos 7 镜像,vagrant box add ceshi 镜像名 或者是使用先前vagrant package出来的box,进行加载镜 ...
- 【面试题】Java实现String的IndexOf方法
先说题后感:程序员这一行,很多时候,自驱学习能力是自我成长一个很重要的因素(当然技术最好的学习途径都是通过项目实践去学习.理解.掌握).而自学方法中,除了看官方文档.技术博客等途径之外,学习源码也是一 ...
- Textarea设置自动高度
$.fn.extend({ autoHeight: function() { return this.each(function() { var $this = jQuery(this); if(!$ ...
- Chrome_高亮显示当前改变的区域
- docker 数据卷管理
在生产环境中使用docker,往往需要对数据进行持久化,或者需要在多个容器之间进行数据共享,这涉及到容器对数据管理的操作 容器对数据的管理主要有两种方式: 数据卷(Data Volumes): 容器内 ...
- 论python中的函数参数的传递问题。
python是完全面向对象的语言,在参数传递的过程不能使用值传递,引用传递的概念,而应该使用immutable和mutable.在java中,除了object,其实还有8种基本数据类型,才有了参数传递 ...
- git 服务器搭建与运用
环境:CentOS 6 为了不影响后面的安装 安装依赖库 yum install curl-devel expat-devel gettext-devel openssl-devel zlib-dev ...