服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - IOS - iOS新增绘制圆的方法实例代码

iOS新增绘制圆的方法实例代码

2021-06-03 15:19CobableKun IOS

这篇文章主要给大家介绍了关于iOS新增绘制圆的方法,文中通过示例代码介绍的非常详细,对各位iOS开发者们具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

ios 的坐标系和我们几何课本中的二维坐标系并不一样!

# bezierpath绘制圆弧

使用 uibezierpath 进行绘制圆弧的方法,通常会直接使用 addarc :

?
1
addarc(withcenter:, radius:, startangle:, endangle:, clockwise:)

或者使用 addcurve 进行拟圆弧:

?
1
addcurve(to:, controlpoint1:, controlpoint2:)

其实我们可以通过,两个坐标点(startpoint & endpoint),和两点间的线段对应的圆弧的弧度(angle/radian)就能确定这个圆的信息(半径radius, center), 所以我们是不是可以封装出只提供 start, end 和 angle 就能绘制 arc 的函数?

?
1
addarc(startpoint: , endpoint: , angle: , clockwise:)

# 计算两点间的距离

这里逻辑很简单不做赘述。

?
1
2
3
4
5
func calculatelinelength(_ point1: cgpoint, _ point2: cgpoint) -> cgfloat {
  let w = point1.x - point2.x
  let h = point1.y - point2.y
  return sqrt(w * w + h * h)
}

# 计算两点间的夹角

计算 point 和 origin 连线在 ios 坐标系的角度

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
func calculateangle(point: cgpoint, origin: cgpoint) -> double {
  
  if point.y == origin.y {
    return point.x > origin.x ? 0.0 : -double.pi
  }
  
  if point.x == origin.x {
    return point.y > origin.y ? double.pi * 0.5 : double.pi * -0.5
  }
  // note: 修正标准坐标系角度到 ios 坐标系
  let rotationadjustment = double.pi * 0.5
  
  let offsetx = point.x - origin.x
  let offsety = point.y - origin.y
  // note: 使用 -offsety 是因为 ios 坐标系与标准坐标系的区别
  if offsety > 0 {
    return double(atan(offsetx / -offsety)) + rotationadjustment
  } else {
    return double(atan(offsetx / -offsety)) - rotationadjustment
  }
}

# 计算圆心的坐标

如果你已经将几何知识丢的差不多了的话,我在这里画了个大概的草图,如下( angle 比较小时):

iOS新增绘制圆的方法实例代码

angle 比较大时:

iOS新增绘制圆的方法实例代码

所以我么可以写出如下计算中心点的代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
// woring: 只计算从start到end **顺时针** 计算对应的 **小于π** 圆弧对应的圆心
// note: 计算逆时针(end到start)可以看做将传入的start和end对调后计算顺时针时的圆心位置
// note: 计算大于π的叫相当于将end和start对换后计算2π-angle的顺时针圆心位置
// note: 综上传入start,end,angle 右外部自行处理逻辑
func calculatecenterfor(startpoint start: cgpoint, endpoint end: cgpoint, radian: double) -> cgpoint {
  guard radian <= double.pi else {
    fatalerror("does not support radian calculations greater than π!")
  }
  
  guard start != end else {
    fatalerror("start position and end position cannot be equal!")
  }
  
  if radian == double.pi {
    let centerx = (end.x - start.x) * 0.5 + start.x
    let centery = (end.y - start.y) * 0.5 + start.y
    return cgpoint(x: centerx, y: centery)
  }
  
  let lineab = calculatelinelength(start, end)
  
  // 平行 y 轴
  if start.x == end.x {
    let centery = (end.y - start.y) * 0.5 + start.y
    let tanresult = cgfloat(tan(radian * 0.5))
    let offsetx = lineab * 0.5 / tanresult
    let centerx = start.x + offsetx * (start.y > end.y ? 1.0 : -1.0)
    return cgpoint(x: centerx, y: centery)
  }
  
  // 平行 x 轴
  if start.y == end.y {
    let centerx = (end.x - start.x) * 0.5 + start.x
    let tanresult = cgfloat(tan(radian * 0.5))
    let offsety = lineab * 0.5 / tanresult
    let centery = start.y + offsety * (start.x < end.x ? 1.0 : -1.0)
    return cgpoint(x: centerx, y: centery)
  }
  
  // 普通情况
  
  // 计算半径
  let radius = lineab * 0.5 / cgfloat(sin(radian * 0.5))
  // 计算与 y 轴的夹角
  let angletoyaxis = atan(abs(start.x - end.x) / abs(start.y - end.y))
  let cacluteangle = cgfloat(double.pi - radian) * 0.5 - angletoyaxis
  // 偏移量
  let offsetx = radius * sin(cacluteangle)
  let offsety = radius * cos(cacluteangle)
  
  var centetx = end.x
  var centery = end.y
  // 以 start 为原点判断象限区间(ios坐标系)
  if end.x > start.x && end.y < start.y {
    // 第一象限
    centetx = end.x + offsetx
    centery = end.y + offsety
  } else if end.x > start.x && end.y > start.y {
    // 第二象限
    centetx = start.x - offsetx
    centery = start.y + offsety
  } else if end.x < start.x && end.y > start.y {
    // 第三象限
    centetx = end.x - offsetx
    centery = end.y - offsety
  } else if end.x < start.x && end.y < start.y {
    // 第四象限
    centetx = start.x + offsetx
    centery = start.y - offsety
  }
  
  return cgpoint(x: centetx, y: centery)
}

这里附上一个逆时针绘制第一张图中圆心位置的草图,图中已将 start 和 end 对换

iOS新增绘制圆的方法实例代码

如果你对其中计算时到底该使用 + 还是 - 有困惑的话也可以自己多画些草图大概验证下,总之有疑惑多动手

延伸 · 阅读

精彩推荐
  • IOSiOS 雷达效果实例详解

    iOS 雷达效果实例详解

    这篇文章主要介绍了iOS 雷达效果实例详解的相关资料,需要的朋友可以参考下...

    SimpleWorld11022021-01-28
  • IOSIOS开发之字典转字符串的实例详解

    IOS开发之字典转字符串的实例详解

    这篇文章主要介绍了IOS开发之字典转字符串的实例详解的相关资料,希望通过本文能帮助到大家,让大家掌握这样的方法,需要的朋友可以参考下...

    苦练内功5832021-04-01
  • IOS解析iOS开发中的FirstResponder第一响应对象

    解析iOS开发中的FirstResponder第一响应对象

    这篇文章主要介绍了解析iOS开发中的FirstResponder第一响应对象,包括View的FirstResponder的释放问题,需要的朋友可以参考下...

    一片枫叶4662020-12-25
  • IOS关于iOS自适应cell行高的那些事儿

    关于iOS自适应cell行高的那些事儿

    这篇文章主要给大家介绍了关于iOS自适应cell行高的那些事儿,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的...

    daisy6092021-05-17
  • IOSIOS 屏幕适配方案实现缩放window的示例代码

    IOS 屏幕适配方案实现缩放window的示例代码

    这篇文章主要介绍了IOS 屏幕适配方案实现缩放window的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要...

    xiari5772021-06-01
  • IOSiOS通过逆向理解Block的内存模型

    iOS通过逆向理解Block的内存模型

    自从对 iOS 的逆向初窥门径后,我也经常通过它来分析一些比较大的应用,参考一下这些应用中某些功能的实现。这个探索的过程乐趣多多,不仅能满足自...

    Swiftyper12832021-03-03
  • IOSiOS布局渲染之UIView方法的调用时机详解

    iOS布局渲染之UIView方法的调用时机详解

    在你刚开始开发 iOS 应用时,最难避免或者是调试的就是和布局相关的问题,下面这篇文章主要给大家介绍了关于iOS布局渲染之UIView方法调用时机的相关资料...

    windtersharp7642021-05-04
  • IOSiOS中tableview 两级cell的展开与收回的示例代码

    iOS中tableview 两级cell的展开与收回的示例代码

    本篇文章主要介绍了iOS中tableview 两级cell的展开与收回的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    J_Kang3862021-04-22