iOS开发之自定义view—Quartz2D
来源:互联网 发布:文艺气息的网名知乎 编辑:程序博客网 时间:2024/05/16 14:08
之前的文章介绍了数据的传递和存储,这篇文章就介绍显示数据的控件。iPhone之所以这么受欢迎,其中有一个原因是因为它的UI界面非常美观。iOS提供了UIKit框架,里面有各种各样的UI控件。
这里有利用Quartz2D生成的图片(包括裁剪圆形图片,截图,水印图片):https://github.com/shihuaixing/ClipCircleImageDemo.git
UILabel:显示文字
UIImageVIew:显示图片
UIButton:同时显示图片和文字,还能点击
等等。
这些控件进行拼拼凑凑是能够搭建和实现一些简单、常见的UI界面,并显示数据的。
但是有些UI界面极其复杂、而且比较有个性,用普通的UI控件是无法实现的,这个时候可以利用Quartz2D技术奖控件内部的结构画出来,就向自定义控件的样子。其实,iOS中大部分控件的内容都是通过Quarz2D画出来的。
因此,Quarz2D在iOS开发中很重要的一个价值就是:自定义view(自定义控件)。
我们来简单了解一下关于Quarz2D的知识。
Quarz2D:是一个二维绘图引擎,同时支持iOS和Mac系统。
Quarz2D的API是纯C语言的。
Quarz2D的API来自于Core Graphics框架
Quarz2D函数类型和函数基本都以CG为前缀:
CGContextRef
CGPathRef
CGContextStrokePath(ctx)
Quarz2D能完成的简单的工作:
1) 绘制图形:线条/三角形/矩形/圆/弧等
2) 绘制文字
3) 绘制/生成图片
4)读取/生成PDF
5)图/裁剪图片
6)定义控件
7)等等
下面来看一下利用Quarz2D实现的一些效果:
1、图片裁剪:
下面我们在使用Quarz2D之前,简单认识一些概念:
1)图形上下文(Graphics Context):是一个CGContextRef类型的数据
a. 作用:
保存绘图信息,绘图状态;
决定绘制的输出目标(绘制到什么地方)
(输出目标客源是PDF文件、Bitmap或者显示器的窗口上)
b. Quarz2D提供了以下几种类型的Graphics Context:
· Bitmap Graphics Context
· PDF Graphics Context
· Window Graphics Context
· Layer Graphics Context
· Printer Graphics Context
注意:图形上下文(Graphics Context)是一个很重要的类型!
了解了图形上下文(GraphicsContext),那我们如何利用Quarz2D自定义view(自定义控件)?
如何利用Quarz2D绘制内容到view上:
1)首先,得有图形上下文,因为它能保存绘图信息,并且决定这绘制到什么地方去
2)其次,那个图形上下文必须跟view想关联,才能讲内容绘制到view上
自定义view的步骤:
1)新建一个类,继承自UIView
2)实现-(void)drawRect:方法,然后在这个方法中
a. 取得跟当前view相关联的图形上下文
b. 绘制相应的图形内容
c. 利用图形上下文将绘制的所有内容渲染显示到view上那大家可能会要问,为什么要实现drawRect:方法才能将绘图显示到view上呢?最重要的一点:因为在drawRect:方法中才能取到跟view相关联的图形上下文。
drawRect:方法在什么时候被执行呢?了解:
1)view内部有个layer(图层)属性,drawRect:方法中取得的是一个Layer GraphicsContext,因此,绘制的内容其实是绘制到view的layer上去了。
2)view之所以能显示东西,完全是因为它内部的layer(图层)
下面通过代码显示Quarz2D的功能:
创建新项目,在控制器view上拖一个自定义view(redView),创建自定义view类(HXView)。将自定义的view的类设置为HXView。
1、画线、画圆、画弧
- (void)drawBasisGraphics { /***************画线*****************/ // 获得图形上下文 CGContextRef ctx = UIGraphicsGetCurrentContext(); // 画线 // 1.起点 CGContextMoveToPoint(ctx, 10, 10); // 添加线段 CGContextAddLineToPoint(ctx, 100, 100); CGContextAddLineToPoint(ctx, 200, 30); // 设置线宽 CGContextSetLineWidth(ctx, 10); // 设置线颜色 CGContextSetRGBStrokeColor(ctx, 1, 0, 0, 1); // 设置两头部样式 CGContextSetLineCap(ctx, kCGLineCapRound); // 设置连接处样式 CGContextSetLineJoin(ctx, kCGLineJoinRound); // 渲染并显示到view上 CGContextStrokePath(ctx); /***************画圆*****************/ // 1.通过椭圆画出圆 // 1)(不填充)// CGContextAddEllipseInRect(ctx, CGRectMake(0, 0, 100, 100));// // // 设置线宽// CGContextSetLineWidth(ctx, 10);// // 设置线颜色// CGContextSetRGBStrokeColor(ctx, 1, 0, 0, 1);// // // 渲染并显示到view上// CGContextStrokePath(ctx); // 2)(填充)// CGContextAddEllipseInRect(ctx, CGRectMake(0, 0, 100, 100));// // // 设置线颜色// CGContextSetRGBFillColor(ctx, 1, 0, 0, 1);// // // 渲染并显示到view上// CGContextFillPath(ctx); // 2.根据圆点、半径(可以画圆弧) // 1)不填充 CGContextAddArc(ctx, 100, 100, 50, 0, M_PI_2, 0); // CGContextAddArc: 参数说明 /* CGContextRef c:图形上下文 CGFloat x, CGFloat y:圆点坐标 CGFloat radius:圆的半径 CGFloat startAngle:画圆的开始角度(逆时针为负,顺时针为正) CGFloat endAngle:画圆的结束角度 int clockwise:画图方向,0:顺时针,1:逆时针 */ // 设置线颜色 CGContextSetRGBStrokeColor(ctx, 1, 0, 0, 1); // 渲染并显示到view上 CGContextStrokePath(ctx); // 2)填充// CGContextAddArc(ctx, 100, 100, 50, 0, M_PI_2, 0);// // 设置线颜色// CGContextSetRGBFillColor(ctx, 1, 0, 0, 1);// // // 渲染并显示到view上// CGContextFillPath(ctx); /***************画弧*****************/ // 当前点 CGContextMoveToPoint(ctx, 50, 100); CGContextAddCurveToPoint(ctx, 0, 0, 100, 100, 50, 0); // set : 同时设置为实心和空心颜色 // setStroke : 设置空心颜色 // setFill : 设置实心颜色 [[UIColor whiteColor] set]; CGContextStrokePath(ctx); }
2、画图,并裁剪
// 画图- (void)drawImage:(CGRect)rect { // 获得图形上下文 CGContextRef ctx = UIGraphicsGetCurrentContext(); UIImage *image = [UIImage imageNamed:@"008.jpg"]; // [image drawAsPatternInRect:rect];// 平铺// [image drawInRect:rect]; // 拉伸 [image drawAtPoint:CGPointMake(0, 0)];// 从父控件的0,0点开始画图 // 渲染显示到view上 CGContextStrokePath(ctx);}
// 裁剪圆形图片- (void)drawCircleImage:(CGRect)rect { // 获得图形上下文 CGContextRef ctx = UIGraphicsGetCurrentContext(); UIImage *image = [UIImage imageNamed:@"008.jpg"]; // 1.画圆 CGContextAddEllipseInRect(ctx, CGRectMake((rect.size.width - image.size.width) * 0.5, (rect.size.height - image.size.height) * 0.5, image.size.height, image.size.width)); // 超出该圆的内容全部裁剪掉 CGContextClip(ctx);// 裁剪当前图形上下文 CGContextClipToRect(ctx, CGRectMake((rect.size.width - image.size.width) * 0.5, (rect.size.height - image.size.height) * 0.5, image.size.height, image.size.width)); // 裁剪范围 // 画图 [image drawAtPoint:CGPointMake((rect.size.width - image.size.width) * 0.5, (rect.size.height - image.size.height) * 0.5)]; CGContextSetLineWidth(ctx, 10); // 渲染显示到view上 CGContextStrokePath(ctx);}
3、画文字(使用Quartz2D画出来的文字是反着的,跟坐标系有关)
- (void)drawText:(CGRect)rect { NSString *textString = @"哈哈哈哈shx"; NSMutableDictionary *attris = [NSMutableDictionary dictionary]; attris[NSFontAttributeName] = [UIFont systemFontOfSize:20]; attris[NSForegroundColorAttributeName] = [UIColor whiteColor]; [textString drawInRect:rect withAttributes:attris];}
下面我们来做一个画板:
清空:清除画板上的所有内容;
回退:清除在画板上画出的最后一条线
创建新项目,在控制器view上拖一个自定义view(redView),创建自定义view类(HXView)。将自定义的view的类设置为HXView。
因为手指要在view上触摸才能有事件发生,所以要在HXView.m文件中重写如下方法:
/** * 手指开始触摸view的时候调用 * 在该方法中可以确定线的起点 */- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {}/** * 手指在view上移动时调用 * 在该方法中连接其他点 */- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { }/** * 手指触摸结束时候调用 * 在该方法中处理一条路径画完之后的事情 */- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { }
先来了解一下思路:
每当手指开始触摸view的时候就会调用touchesBegan方法,每次调用该方法时就创建一个新的路径(path:n个点组成),把touchesBegan获得的点(起点)添加到这条新的路径中(数组存储点);当手指在view上移动的时候就会调用touchesMoved方法,每次调用该方法就会返回手指所在的位置,把该位置添加到path中;当手指在view上触摸结束的时候就会调用touchesEnded方法,在该方法中项path中添加最后的一个点。至此,path路径上的所有点都被存储在path中了。现在可以利用view的drawRect:方法开始绘制路径了。
由于画板可能会绘制很对条路径,所以我们也要把所有的路径存起来。(数组存储路径)
注意:每次向path中添加点的时候都要主动调用setNeedsDisplay方法,该方法会调用drawRect:方法随时绘制路径。
现在来实现这些方法
在touchesBegan方法中,能获得手指开始触摸时候的位置(一个路径的起点)
/** * 手指开始触摸view的时候调用 * 在该方法中可以确定线的起点 */- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { // 获得开始触摸的点(起点) CGPoint startPoint = [self pointWithTouch:touches]; // 存储新路径上的所有的点 NSMutableArray *currentPath = [NSMutableArray array]; // 新路径存储新路径的第一个点(新路径起点) [currentPath addObject:[NSValue valueWithCGPoint:startPoint]]; // 将新路径存储到数组中 [self.paths addObject:currentPath]; // 重新绘制 [self setNeedsDisplay];}
获得点的方法
- (CGPoint)pointWithTouch:(NSSet * )touches { UITouch *touch = [touches anyObject]; CGPoint point = [touch locationInView:touch.view]; return point;}
手指开始移动:
/** * 手指在view上移动时调用 * 在该方法中连接其他点 */- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { // 获取其他点 CGPoint otherPoint = [self pointWithTouch:touches]; // 取出最后一个路径(当前正在画的路径) NSMutableArray *currentPath = [self.paths lastObject]; // 存储其他点 [currentPath addObject:[NSValue valueWithCGPoint:otherPoint]]; // 重新绘制 [self setNeedsDisplay]; }
手指触摸事件结束:(考虑为什么只要调用touchesMoved方法)
/** * 手指触摸结束时候调用 * 在该方法中处理一条路径画完之后的事情 */- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { // 手指离开后,也是连接点 [self touchesMoved:touches withEvent:event]; }
回退功能(移除存储路径的数组的最后一个元素):
- (void)revoke { [self.paths removeLastObject]; [self setNeedsDisplay]; }
清空功能(移除存储路径的数组的所有元素);
- (void)clear { [self.paths removeAllObjects]; [self setNeedsDisplay];}注意:每次改变路径内容的时候都要调用setNeedsDisplay方法!
效果:
回退:
清空:
只要自定义一个view,实现它的drawRect:方法,就可以在这个view上画出你想要的内容。大家可以试着实现以下前途的手势解锁功能的界面。(以上部分图片引用自mj老师)
- iOS开发之自定义view—Quartz2D
- IOS-自定义锯齿形背景view,使用quartz2d
- iOS开发之自定义View
- iOS开发之自定义View
- iOS开发之自定义View
- iOS开发之Quartz2D详解
- IOS开发之Quartz2D绘图
- iOS开发UI篇—Quartz2D(自定义UIImageView控件)
- iOS开发UI高级—37Quartz2D(自定义UIImageView控件)
- iOS开发UI篇—Quartz2D(自定义UIImageView控件)
- iOS开发UI篇—Quartz2D(自定义UIImageView控件)
- iOS开发UI篇—Quartz2D(自定义UIImageView控件)
- iOS开发UI篇—Quartz2D(自定义UIImageView控件)
- iOS开发——Quartz2D
- IOS开发之——自定义的Activity Indicator View
- IOS开发之——自定义的Activity Indicator View
- 详解iOS开发之自定义View
- iOS开发之Quartz2D生成PDF-Part1
- C/C++程序从编译到最终生成可执行文件的过程分析
- linux下查看文件编码及修改编码
- MATLAB常用数学函数
- 抽象类
- hello-world
- iOS开发之自定义view—Quartz2D
- 【数据传输 1】服务器—>客户端之间的数据类型转换
- 【Android Studio】制作启动画面Splash Screen
- 我们如何使用Hibernate的锁(悲观锁)
- 条件编译
- POJ-1276-Cash Machine-多重背包
- object-c之UITableView数据的编辑
- 410c与MS10物联网系统的点灯代码分析
- android---Scroll实现滑动效果