UIBezierPath是对Core Graphics框架的一种上层封装,目的是让绘图需求可以被更方便的使用。
那你有没有发现被UIBezierPath封装后与之前有什么改变?
答:有三个变化。
1.屏蔽繁杂重复的内容
2.功能阉割
3.坐标系顺时针方向反转
 
证明1:屏蔽繁杂重复的内容
相比Core Graphics框架,UIBezierPath帮我们做了一些繁琐的事件。比如有这样一个场景:需要画一个圆,但是它的每个1/4弧线的strokpath颜色是不同的。对于这样的需求。
有个错误的做法是:
1.拿到上下文
2.设置第一个1/4户的strokpath颜色,用上下文绘制第一个1/4弧
3.设置第一个2/4户的strokpath颜色,用上下文绘制第一个2/4弧
4.设置第一个3/4户的strokpath颜色,用上下文绘制第一个3/4弧
5.设置第一个4/4户的strokpath颜色,用上下文绘制第一个4/4弧
最后的结果会发现,这四段弧的颜色是最后一个4/4弧的strokpath的颜色
原因是:对于一个上下文来说,strokPathColor属性只有一个,虽然设置了4次,但总是后面的覆盖前面的。
 
一种解决方法是:
在第2步之前,先循环4次操作
  1. let content = UIGraphicsGetCurrentContext()
  2. content?.setStrokeColor(UIColor.blue.cgColor)
  3. content?.saveGState()
然后在每一步绘制前,恢复上下文栈中的存储到当前上下文

  1. content?.restoreGState()
另一种解决方法是:
直接创建4个UIBezierPath,用贝塞尔曲线绘制着4段弧。
这样就很直观的看出,每个UIBezierPath的上下文都是独立的。内部帮我们自己做了上下文的存栈和出栈。
 
证明2:功能阉割
虽然有了UIBezierPath的封装我们用起来方便了,但是相应的代价是所提供的功能被阉割了。有些强大的功能UIBezierPath没有提供实现,比如:现在要画一个圆形的渐变球,就只能使用Core Graphics框架。
代码如下
  1. //利用上下文绘制渐变色(圆形)
  2. let context = UIGraphicsGetCurrentContext()
  3. //颜色空间
  4. let colorSpace = CGColorSpaceCreateDeviceRGB()
  5. let startColor = UIColor.black
  6. let endColor = UIColor.red
  7. //颜色数组
  8. let colors = [startColor.cgColor,endColor.cgColor]
  9. //颜色所处位置
  10. let locations:[CGFloat] = [,]
  11. let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as! CFArray, locations: locations)
  12. let center = CGPoint(x: rect.size.width*0.5, y: rect.size.height*0.5)
  13. let radius = rect.size.height*0.3
  14. context?.drawRadialGradient(gradient!, startCenter: center, startRadius: radius*0.2, endCenter: center, endRadius: radius, options: CGGradientDrawingOptions.drawsBeforeStartLocation)
证明3:坐标系顺时针方向反转
你知道吗, CoreGraphics绘图系统和Bezier贝塞尔曲线坐标系的顺时针方向是相反的!
 
我记得上学时老师讲的坐标系是这样的: 

X轴指向右侧,Y轴指向上面。对应的弧度如图上标的那样。顺时针也是钟表表针转动的方向。这就是最早接触的坐标系,熟悉的单纯模样。

在工作时,当我们往屏幕上布局UI时,用到的坐标系是下面这样:

对于UI控件来讲的坐标系模式,X轴方向向右,Y轴方向向下。
请注意弧度值也相应的转了方向,它是沿着X,Y指向的方向开始逐渐增加的。
顺时针还是熟悉的钟表表针转动方向。
 
关键代码如下:
  1. let content = UIGraphicsGetCurrentContext()
  2.  
  3. var endAngl = _progressValue*CGFloat(M_PI*)
  4. var clockState = (_direction == .onTime)
  5.  
  6. //圆
  7. var des: String = ""
  8. des = clockState ? "UIGraphics上下文绘制、顺时针" : "UIGraphics上下文绘制、逆时针”
  9.  
  10. content?.move(to: CGPoint(x: width-arcRadius, y: height*0.5))
  11. let bez = UIBezierPath(arcCenter: arcCenter, radius: arcRadius, startAngle: , endAngle: endAngl, clockwise: clockState)
  12. content?.addPath(bez.cgPath)
  13.  
  14. NSString(string: des).draw(in: CGRect(x: , y: , width: width*0.4, height: height*0.5), withAttributes: atts)
  15. log = String(format: "绘制弧度: %.4f Pi", endAngl/3.14)
  16.  
  17. content?.strokePath()

实际效果图如下:

UIBezierPath顺时针模式下,从0到2PI的效果
 
UIBezierPath逆时针模式下,从0到2PI的效果
然后突出的CoreGraphics表示不服,我就要与众不同。如下图:

说出来你可能不信,你会发现顺时针方向往上了。这明明是逆时针方向啊!WTF?

来看下代码和实现效果吧。

  1. let content = UIGraphicsGetCurrentContext()
  2.  
  3. var endAngl = _progressValue*CGFloat(M_PI*2)
  4. var clockState = (_direction == .onTime)
  5.  
  6. //圆
  7. var des: String = ""
  8. des = clockState ? "UIGraphics上下文绘制、顺时针" : "UIGraphics上下文绘制、逆时针”
  9.  
  10. content?.move(to: CGPoint(x: width-arcRadius, y: height*0.5))
  11. content?.addArc(center: arcCenter, radius: arcRadius, startAngle: 0, endAngle: endAngl, clockwise: clockState)
  12.  
  13. NSString(string: des).draw(in: CGRect(x: 2, y: 2, width: width*0.4, height: height*0.5), withAttributes: atts)
  14. log = String(format: "绘制弧度: %.4f Pi", endAngl/3.14)
  15.  
  16. content?.strokePath()

实际效果如下:

CoreGraphics顺时针模式下,从0到2PI的效果

CoreGraphics逆时针模式下,从0到2PI的效果

CoreGraphics和Bezier贝塞尔曲线都是平时开发中的利器,认真品味一下两者的区别,会让我们对它们有更深的认识。

有讲的不对的地方欢迎指正。

Demo地址:https://github.com/zhfei/CoordinateSystem

你知道吗, CoreGraphics绘图系统和Bezier贝塞尔曲线坐标系的顺时针方向是相反的!的更多相关文章

  1. 下一代大数据系统和4S标准

    大数据行业发展到今天,它创造的价值和带来的社会效应,大家已经看得很明白,同时很多问题和不足也暴露出来,特别是hadoop能够提供的数据处理能力,现在已经挖掘到极限,但是现在各行业对数据的存储和计算需求 ...

  2. 操作系统和Python的发展历程

    一:操作系统的发展历史: 操作系统:什么是操作系统?我们首先想到的是电脑,,也就是所谓的Windows8,Windows7,或者XP系统和Windows10,当然也包括我们手机的安卓系统或者IPhon ...

  3. 使用拷贝的方式(adb push) 绕过Android系统和adb install直接安装APK

    某些情况下定制的Android系统为了限制用户安装应用,例如电视盒子,车载中控等,通过修改代码屏蔽了正常安装应用的方式 本文探讨如何在 adb shell 具有读写data分区目录的权限前提下,通过a ...

  4. GNU构建系统和AutoTools

    注:本篇博客是阅读文末[参考博客]的讲解所写,内容非原创,仅是学习笔记 1. 概述2. 不同视角的程序构建2.1 用户视角2.2 开发者视角3. 导图图片4. configure选项参考博客 1. 概 ...

  5. android系统和ios系统是如何实现推送的,ios为什么没有后台推送

    ios系统为什么没有后台推送? iOS 为了真正地为用户体验负责,不允许应用在后台活动.有了这个限制,但是对于终端设备,应用又是有必要“通知”到达用户的,随时与用户主动沟通起来的(典型的如聊天应用). ...

  6. gpio子系统和pinctrl子系统(下)

    情景分析 打算从两个角度来情景分析,先从bsp驱动工程师的角度,然后是驱动工程师的角度,下面以三星s3c6410 Pinctrl-samsung.c为例看看pinctrl输入参数的初始化过程(最开始的 ...

  7. gpio子系统和pinctrl子系统(上)

    前言 随着内核的发展,linux驱动框架在不断的变化.很早很早以前,出现了gpio子系统,后来又出现了pinctrl子系统.在网上很难看到一篇讲解这类子系统的文章.就拿gpio操作来说吧,很多时候都是 ...

  8. 一种基于uCos-II操作系统和lwIP协议栈的IEEE-1588主站以及基于该主站的报文处理方法

    主站以及应用于电力系统的支持IEEE‐1588协议的主时钟(IEEE‐1588主站)的实现方法.该方法是在一个低成本的硬件平台上,借助uCos‐II操作系统和TCP/IP的协议栈,对以太网数据进行了分 ...

  9. 基于GPS北斗卫星授时系统和NTP网络授时服务器的设计与开发

    基于GPS北斗卫星授时系统和NTP网络授时服务器的设计与开发 安徽京准科技提供@请勿转载@@ 更多资料请参考——ahjzsz.com 天文观测设备对于控制系统的时间准确度有严格要求.为此,采用搭建高精 ...

随机推荐

  1. A - 还是畅通工程(最小生成树)

    点击打开链接 某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离.省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并 ...

  2. leecode刷题(20)-- 删除链表中的节点

    leecode刷题(20)-- 删除链表中的节点 删除链表中的节点 描述: 请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点. 现有一个链表 -- head = ...

  3. Python dict转化为string方法

    dict-->string: str() string-->dict eval()(这个只是网上看的,没实测)

  4. html中object和embed标签的区别

    ♦object定义一个嵌入的对象.请使用此元素向您的 XHTML 页面添加多媒体.此元素允许您规定插入 HTML 文档中的对象的数据和参数,以及可用来显示和操作数据的代码. ♦<object&g ...

  5. GPS坐标转百度地图坐标

    百度地图提供了相关API:BMap.Convertor.translate, 但是使用上存在部分限制:1.次数限制:2.异步回调 可以用如下方法: /** * 地图位置计算工具(将GPS坐标转换成百度 ...

  6. mysql随机取出若干条记录的实用方法

    1.常见的方法 ; 这种方法可以随机取得数据,但是如果表比较大,数据量很多的时候会很耗时. 2.优化后的方式 ) as t ); 分析,首先根据条件筛选出要选的数据,然后随机排序取出要的条数的id , ...

  7. P2278 操作系统

    P2278 操作系统 题目描述 写一个程序来模拟操作系统的进程调度.假设该系统只有一个CPU,每一个进程的到达时间,执行时间和运行优先级都是已知的.其中运行优先级用自然数表示,数字越大,则优先级越高. ...

  8. P1975 [国家集训队]排队

    题目链接 题意分析 我们考虑 交换两个数\([le,ri]\)的贡献 减少的逆序对数\([le,ri]\)中小于\(num[le]\)以及大于\(num[ri]\)的数 增加的\([le,ri]\)中 ...

  9. ORACLE 动态执行SQL语句

    本文转自 http://zhaisx.iteye.com/blog/856472 Oracle 动态SQL Oracle 动态SQL有两种写法:用 DBMS_SQL 或 execute immedia ...

  10. 网络编程-echo服务器

    代码: #coding="utf-8" #name=echo服务器 from socket import * #1.创建套接字 udpSocket = socket(AF_INET ...