UIBezierPath

学习UIBezierPath画图


笔者在写本篇文章之前,也没有系统学习过贝塞尔曲线,只是曾经某一次的需求需要使用到,才临时百度看了一看而且使用最基本的功能。现在总算有时间停下来好好研究研究这个神奇而伟大的贝塞尔先生!

笔者在学习时,首先看了两遍UIBezierPath类头文件定义,熟悉了一下相关的属性和方法。

支持原创,请阅读原文

基础知识


使用UIBezierPath可以创建基于矢量的路径,此类是Core Graphics框架关于路径的封装。使用此类可以定义简单的形状,如椭圆、矩形或者有多个直线和曲线段组成的形状等。

UIBezierPathCGPathRef数据类型的封装。如果是基于矢量形状的路径,都用直线和曲线去创建。我们使用直线段去创建矩形和多边形,使用曲线去创建圆弧(arc)、圆或者其他复杂的曲线形状。

使用UIBezierPath画图步骤:

  1. 创建一个UIBezierPath对象
  2. 调用-moveToPoint:设置初始线段的起点
  3. 添加线或者曲线去定义一个或者多个子路径
  4. 改变UIBezierPath对象跟绘图相关的属性。如,我们可以设置画笔的属性、填充样式等

UIBezierPath创建方法介绍


我们先看看UIBezierPath类提供了哪些创建方式,这些都是工厂方法,直接使用即可。

+ (instancetype)bezierPath;
+ (instancetype)bezierPathWithRect:(CGRect)rect;
+ (instancetype)bezierPathWithOvalInRect:(CGRect)rect;
+ (instancetype)bezierPathWithRoundedRect:(CGRect)rectcornerRadius:(CGFloat)cornerRadius;
+ (instancetype)bezierPathWithRoundedRect:(CGRect)rectbyRoundingCorners:(UIRectCorner)corners cornerRadii:(CGSize)cornerRadii;
+ (instancetype)bezierPathWithArcCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise;
+ (instancetype)bezierPathWithCGPath:(CGPathRef)CGPath;

下面我们一个一个地介绍其用途。

+ (instancetype)bezierPath;

这个使用比较多,因为这个工厂方法创建的对象,我们可以根据我们的需要任意定制样式,可以画任何我们想画的图形。

+ (instancetype)bezierPathWithRect:(CGRect)rect;

这个工厂方法根据一个矩形画贝塞尔曲线。

+ (instancetype)bezierPathWithOvalInRect:(CGRect)rect;

这个工厂方法根据一个矩形画内切曲线。通常用它来画圆或者椭圆。

+ (instancetype)bezierPathWithRoundedRect:(CGRect)rectcornerRadius:(CGFloat)cornerRadius;
+ (instancetype)bezierPathWithRoundedRect:(CGRect)rectbyRoundingCorners:(UIRectCorner)corners cornerRadii:(CGSize)cornerRadii;

第一个工厂方法是画矩形,但是这个矩形是可以画圆角的。第一个参数是矩形,第二个参数是圆角大小。
第二个工厂方法功能是一样的,但是可以指定某一个角画成圆角。像这种我们就可以很容易地给UIView扩展添加圆角的方法了。

+ (instancetype)bezierPathWithArcCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise;

这个工厂方法用于画弧,参数说明如下:
center: 弧线中心点的坐标
radius: 弧线所在圆的半径
startAngle: 弧线开始的角度值
endAngle: 弧线结束的角度值
clockwise: 是否顺时针画弧线

温馨提示:我们下面的代码都是在自定义的BezierPathView类中的- (void)drawRect:(CGRect)rect方法中调用

画三角形


先看效果图:


image
// 画三角形
- (void)drawTrianglePath {UIBezierPath *path = [UIBezierPath bezierPath];[path moveToPoint:CGPointMake(20, 20)];[path addLineToPoint:CGPointMake(self.frame.size.width - 40, 20)];[path addLineToPoint:CGPointMake(self.frame.size.width / 2, self.frame.size.height - 20)];// 最后的闭合线是可以通过调用closePath方法来自动生成的,也可以调用-addLineToPoint:方法来添加//  [path addLineToPoint:CGPointMake(20, 20)];[path closePath];// 设置线宽path.lineWidth = 1.5;// 设置填充颜色UIColor *fillColor = [UIColor greenColor];[fillColor set];[path fill];// 设置画笔颜色UIColor *strokeColor = [UIColor blueColor];[strokeColor set];// 根据我们设置的各个点连线[path stroke];
}

我们设置画笔颜色通过set方法:

UIColor *strokeColor = [UIColor blueColor];
[strokeColor set];

如果我们需要设置填充颜色,比如这里设置为绿色,那么我们需要在设置画笔颜色之前先设置填充颜色,否则画笔颜色就被填充颜色替代了。也就是说,如果要让填充颜色与画笔颜色不一样,那么我们的顺序必须是先设置填充颜色再设置画笔颜色。如下,这两者顺序不能改变。因为我们设置填充颜色也是跟设置画笔颜色一样调用UIColor-set方法。

// 设置填充颜色
UIColor *fillColor = [UIColor greenColor];
[fillColor set];
[path fill];// 设置画笔颜色
UIColor *strokeColor = [UIColor blueColor];
[strokeColor set];

画矩形


先看效果图:


image
// 画矩形
- (void)drawRectPath {UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(20, 20, self.frame.size.width - 40, self.frame.size.height - 40)];path.lineWidth = 1.5;path.lineCapStyle = kCGLineCapRound;path.lineJoinStyle = kCGLineJoinBevel;// 设置填充颜色UIColor *fillColor = [UIColor greenColor];[fillColor set];[path fill];// 设置画笔颜色UIColor *strokeColor = [UIColor blueColor];[strokeColor set];// 根据我们设置的各个点连线[path stroke];
}

lineCapStyle属性是用来设置线条拐角帽的样式的,其中有三个选择:

/* Line cap styles. */typedef CF_ENUM(int32_t, CGLineCap) {kCGLineCapButt,kCGLineCapRound,kCGLineCapSquare
};

其中,第一个是默认的,第二个是轻微圆角,第三个正方形。

lineJoinStyle属性是用来设置两条线连结点的样式,其中也有三个选择:

/* Line join styles. */typedef CF_ENUM(int32_t, CGLineJoin) {kCGLineJoinMiter,kCGLineJoinRound,kCGLineJoinBevel
};

其中,第一个是默认的表示斜接,第二个是圆滑衔接,第三个是斜角连接。

画圆


我们可以使用+ bezierPathWithOvalInRect:方法来画圆,当我们传的rect参数是一下正方形时,画出来的就是圆。

先看效果图:


image
- (void)drawCiclePath {// 传的是正方形,因此就可以绘制出圆了UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(20, 20, self.frame.size.width - 40, self.frame.size.width - 40)];// 设置填充颜色UIColor *fillColor = [UIColor greenColor];[fillColor set];[path fill];// 设置画笔颜色UIColor *strokeColor = [UIColor blueColor];[strokeColor set];// 根据我们设置的各个点连线[path stroke];
}

注意:要画圆,我们需要传的rect参数必须是正方形哦!

画椭圆


先看效果图:


image

前面我们已经画圆了,我们可以使用+ bezierPathWithOvalInRect:方法来画圆,当我们传的rect参数是一下正方形时,画出来的就是圆。那么我们要是不传正方形,那么绘制出来的就是椭圆了。

// 画椭圆
- (void)drawOvalPath {// 传的是不是正方形,因此就可以绘制出椭圆圆了UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(20, 20, self.frame.size.width - 80, self.frame.size.height - 40)];// 设置填充颜色UIColor *fillColor = [UIColor greenColor];[fillColor set];[path fill];// 设置画笔颜色UIColor *strokeColor = [UIColor blueColor];[strokeColor set];// 根据我们设置的各个点连线[path stroke];
}

画带圆角的矩形


+ (instancetype)bezierPathWithRoundedRect:(CGRect)rectcornerRadius:(CGFloat)cornerRadius;
+ (instancetype)bezierPathWithRoundedRect:(CGRect)rectbyRoundingCorners:(UIRectCorner)corners cornerRadii:(CGSize)cornerRadii;

第一个工厂方法是画矩形,但是这个矩形是可以画圆角的。第一个参数是矩形,第二个参数是圆角大小。
第二个工厂方法功能是一样的,但是可以指定某一个角画成圆角。像这种我们就可以很容易地给UIView扩展添加圆角的方法了。

四个都是圆角10:


image
- (void)drawRoundedRectPath {UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(20, 20, self.frame.size.width - 40, self.frame.size.height - 40) cornerRadius:10];// 设置填充颜色UIColor *fillColor = [UIColor greenColor];[fillColor set];[path fill];// 设置画笔颜色UIColor *strokeColor = [UIColor blueColor];[strokeColor set];// 根据我们设置的各个点连线[path stroke];
}

如果要画只有一个角是圆角,那么我们就修改创建方法:

UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(20, 20, self.frame.size.width - 40, self.frame.size.height - 40) byRoundingCorners:UIRectCornerTopRight cornerRadii:CGSizeMake(20, 20)];

其中第一个参数一样是传了个矩形,第二个参数是指定在哪个方向画圆角,第三个参数是一个CGSize类型,用来指定水平和垂直方向的半径的大小。看下效果图:


image

画弧


画弧前,我们需要了解其参考系,如下图(图片来自网络):


image
#define   kDegreesToRadians(degrees)  ((pi * degrees)/ 180)
- (void)drawARCPath {const CGFloat pi = 3.14159265359;CGPoint center = CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2);UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:centerradius:100startAngle:0endAngle:kDegreesToRadians(135)clockwise:YES];path.lineCapStyle = kCGLineCapRound;path.lineJoinStyle = kCGLineJoinRound;path.lineWidth = 5.0;UIColor *strokeColor = [UIColor redColor];[strokeColor set];[path stroke];
}

效果图如下:


image

我们要明确一点,画弧参数startAngleendAngle使用的是弧度,而不是角度,因此我们需要将常用的角度转换成弧度。对于效果图中,我们设置弧的中心为控件的中心,起点弧度为0,也就是正东方向,而终点是135度角的位置。如果设置的clockwise:YES是逆时针方向绘制,如果设置为NO,效果如下:


image

这两者正好是相反的。

画二次贝塞尔曲线


先来学习一下关于控制点,如下图(图片来自网络):


image

画二次贝塞尔曲线,是通过调用此方法来实现的:

- (void)addQuadCurveToPoint:(CGPoint)endPoint controlPoint:(CGPoint)controlPoint

参数说明:

endPoint:终端点<br/>
controlPoint:控制点,对于二次贝塞尔曲线,只有一个控制点

看效果图:


image
- (void)drawSecondBezierPath {UIBezierPath *path = [UIBezierPath bezierPath];// 首先设置一个起始点[path moveToPoint:CGPointMake(20, self.frame.size.height - 100)];// 添加二次曲线[path addQuadCurveToPoint:CGPointMake(self.frame.size.width - 20, self.frame.size.height - 100)controlPoint:CGPointMake(self.frame.size.width / 2, 0)];path.lineCapStyle = kCGLineCapRound;path.lineJoinStyle = kCGLineJoinRound;path.lineWidth = 5.0;UIColor *strokeColor = [UIColor redColor];[strokeColor set];[path stroke];
}

画二次贝塞尔曲线的步骤:

  1. 先设置一个起始点,也就是通过-moveToPoint:设置
  2. 调用-addQuadCurveToPoint:controlPoint:方法设置终端点和控制点,以画二次曲线

在效果图中,拱桥左边的起始点就是我们设置的起始点,最右边的终点,就是我们设置的终端点,而我们设置的控制点为(width / 2, 0)对应于红色矩形中水平方向在正中央,而垂直方向在最顶部。

这个样式看起来很像sin或者cos函数吧?这两个只是特例而已,其实可以画任意图形,只是想不到,没有做不到的。

画三次贝塞尔曲线


贝塞尔曲线必定通过首尾两个点,称为端点;中间两个点虽然未必要通过,但却起到牵制曲线形状路径的作用,称作控制点。关于三次贝塞尔曲线的控制器,看下图:


image

提示:其组成是起始端点+控制点1+控制点2+终止端点

如下方法就是画三次贝塞尔曲线的关键方法,以三个点画一段曲线,一般和-moveToPoint:配合使用。

- (void)addCurveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2

看下效果图:


image

实现代码是这样的:

- (void)drawThirdBezierPath {UIBezierPath *path = [UIBezierPath bezierPath];// 设置起始端点[path moveToPoint:CGPointMake(20, 150)];[path addCurveToPoint:CGPointMake(300, 150)controlPoint1:CGPointMake(160, 0)controlPoint2:CGPointMake(160, 250)];path.lineCapStyle = kCGLineCapRound;path.lineJoinStyle = kCGLineJoinRound;path.lineWidth = 5.0;UIColor *strokeColor = [UIColor redColor];[strokeColor set];[path stroke];
}

我们需要注意,这里确定的起始端点为(20,150),终止端点为(300, 150),基水平方向是一致的。控制点1的坐标是(160,0),水平方向相当于在中间附近,这个参数可以调整。控制点2的坐标是(160,250),如果以两个端点的连线为水平线,那么就是250-150=100,也就是在水平线下100。这样看起来就像一个sin函数了。



文/标哥的技术博客(简书作者)
原文链接:http://www.jianshu.com/p/734b34e82135
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/458558.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

系统架构设计理论与原则

一、无共享架构 1、无共享架构 无共享架构是一种分布式计算架构&#xff0c;这种架构中不存在集中存储的状态&#xff0c;系统中每个节点都是独立自治的&#xff0c;整个系统中没有资源竞争&#xff0c;这种架构具有非常强的扩张性&#xff0c;目前在web应用中被广泛使用。 无共…

VS2010 教程:创建一个 WPF 应用程序 (第一节)

来自&#xff1a;https://msdn.microsoft.com/zh-cn/library/ff629048.aspx [原文发表地址] VS2010 Tutorial: Build a WPF App (Step 1) [原文发表时间] Friday, May 22, 2009 8:00 AM 这篇文章里&#xff0c;我将使用VS2010 Beta 1创建一个WPF 应用程序。并且 我将展示这个产…

js 日期星期 带农历

Weekday代码 //得到当前日期如2009年6月19日 星期五 function getDate(){ var today new Date(); var x new Array("星期日", "星期一", "星期二","星期三","星期四", "星期五","星期六"…

FMDB的使用

// // FMDBmanager.h // database // // Created by PRL on 16/10/13. // Copyright © 2016年PRL. All rights reserved. // #import <Foundation/Foundation.h> interface FMDBmanager : NSObject{ FMDatabase * _db; } (FMDBmanager *)sharedManager; //获取…

深入浅出WPF之Binding的使用(一)

from: http://www.cnblogs.com/akwwl/p/3421005.html 在WPF中Binding可以比作数据的桥梁&#xff0c;桥梁的两端分别是Binding的源&#xff08;Source&#xff09;和目标&#xff08;Target&#xff09;。 一般情况下&#xff0c;Binding源是逻辑层对象&#xff0c;Binding目…

arm处理器中a5 a8 a9,v6 v7,arm7 arm9 arm11都是依据什么来分类的【转】

转自&#xff1a;http://blog.csdn.net/maochengtao/article/details/9951131ARM处理器发展这么多年&#xff0c;有很多架构&#xff0c;很多不同的内核 架构有armv1 v2 v3 v4 v5 v6 v7 内核太多了&#xff0c;比如armv1对应的是arm1&#xff0c;armv5对应的arm9&#xff0c;ar…

前端开发一些很有用的工具

apiview.com 接口规范管理平台 restClient 谷歌浏览器接口测试工具 postman 接口测试工具 SSH Secure Shell Client 抓包工具 SSH SecureFile Transfer Client wireshark 抓包分析工具 Xshell linux远程工具 Balsamiq Mockups 原型图 visio 流程图 xmind top图 SourceCounter、…

所有的iPhone设备cell的宽度都是320,解决办法是?

-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { self [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { self.frameCGRectMake(0, 0, SW, 44); } return self; } 自己重设一下宽度就行了

深入浅出WPF之Binding的使用(二)

from: http://www.cnblogs.com/akwwl/p/3421250.html 在上一篇中介绍了Binding的基本绑定方法&#xff0c;这一篇中我们在深入的介绍Binding的其他用法。 Binding的源也就是数据的源头&#xff0c;在日常的工作中&#xff0c;除了使用像上一篇中的Student对象作为数据源外&a…

iOS 推送

最近在研究ios的推送问题&#xff0c;遇到了一些问题&#xff0c;最终整理了一下。放在这里和大家分享APNS的推送机制首先我们看一下苹果官方给出的对ios推送机制的解释。如下图 Provider就是我们自己程序的后台服务器&#xff0c;APNS是Apple Push Notification Service的缩写…

Bash判断文件夹(目录)是否存在

1 #!/bin/bash 2 if [ -d DirName ]; then 3 echo Dir exist 4 else 5 echo Dir not exist 6 fi 转载于:https://www.cnblogs.com/imzye/p/5059031.html

iOS 加载本地html文件详细操作

webView的加载&#xff0c;如果是纯文本&#xff0c;有内部样式的话&#xff0c;简单的加载请求就可以了。如下: 这种加载简单直接&#xff0c;易操作。 如果需要加载images&#xff0c;css文件 需要把xcode的项目请求路径的位置告诉webView.代码如下&#xff1a; 这样html文件…

HDU 5573 Binary Tree 构造

Binary Tree题目连接&#xff1a; http://acm.hdu.edu.cn/showproblem.php?pid5573 Description The Old Frog King lives on the root of an infinite tree. According to the law, each node should connect to exactly two nodes on the next level, forming a full binary…

志邦橱柜坑爹,志邦橱柜大忽悠,志邦橱柜欺骗

本人实实在在经历的&#xff0c;志邦橱柜就是个大忽悠,志邦橱柜没诚信!! 志邦橱柜先骗客户下订单,在预算时低开,到真正签合同时&#xff0c;不仅仅尺寸坑你,一大堆增项都会出来,原本1.5w预算到最后签合同总价到2.2w,签合同增项高开最后志邦橱柜总价超预算非常非常离谱&#xff…

多线程的那点儿事(之读写锁)

在编写多线程的时候&#xff0c;有一种情况是十分常见的。那就是&#xff0c;有些公共数据修改的机会比较少。相比较改写&#xff0c;它们读的机会反而高的多。通常而言&#xff0c;在读的过程中&#xff0c;往往伴随着查找的操作&#xff0c;中间耗时很长。给这种代码段加锁&a…

iOS获取设备IP

获取iOS设备IP wifi和流量环境下 在网上找的比较好的获取ip的代码 #include <ifaddrs.h> #include <arpa/inet.h> #include <net/if.h> #define IOS_CELLULAR "pdp_ip0" #define IOS_WIFI "en0" #define IOS_VPN …

一些不错的网站

http://www.huxiu.com/虎嗅网&#xff0c;一个关注最新创业信息的网站http://36kr.com/创业天花板https://www.zhihu.com/与世界分享你的经验http://www.mafengwo.cn/世界那么大&#xff0c;想去哪就去那http://www.mt-bbs.com/找到属于自己的设计本http://www.guokr.com/科技有…

[原]详解如何将cocos2dx项目编译到Android平台上的(方式一:Cywin+NDK)

链接地址&#xff1a;http://m.blog.csdn.net/blog/yhc13429826359/29357815 2014-6-8阅读578 评论0 前言&#xff1a;cocos2dx作为一个开源的移动2D游戏框架&#xff0c;其跨平台的特性让它备受开发公司的欢迎。这里我就不做概念性的解释了&#xff0c;通过这篇文章你就会了解…

互斥锁和读写锁的区别

原文地址&#xff1a;http://blog.csdn.NET/u012884354/article/details/46691761 相交进程之间的关系主要有两种&#xff0c;同步与互斥。 所谓互斥&#xff0c;是指散布在不同进程之间的若干程序片断&#xff0c;当某个进程运行其中一个程序片段时&#xff0c;其它进程就不能…

JSP EL表达式使用

为什么80%的码农都做不了架构师&#xff1f;>>> ##1.EL全名为Expression Language out.print(str) <%str%> ${str}例子&#xff1a; Hi! <%username%> 和 Hi! ${username}是一样的 只要是支持servlet2.4/jsp2.0的Container就都可以在jsp网页中直接使用e…