一、创建徽章视图

  • 创建徽章前需要使用 SwiftUI 的矢量绘画 API 创建一个徽章视图:

  • 选择文件 -> 新建 -> 文件,然后从 iOS 文件模板列表中选择 SwiftUI View,点击下一步(Next),输入文件名 Badge 后点击创建 (Create):

  • 调整 Badge 视图,暂时先让它显示“Badge”文本,稍后再绘制徽章的形状:

二、绘制徽章背景

  • 使用 SwiftUI 的图形 API 绘制一个徽章形状:

  • 查看在文件 HexagonParameters.swift 中的代码,HexagonParameters 结构体定义了绘制徽章六边形形状的控制点参数,不需要修改这些绘制相关的数据,仅仅使用这些数据指定绘制徽章形状时,线段和曲线的控制点位置:
struct HexagonParameters {struct Segment {let useWidth: (CGFloat, CGFloat, CGFloat)let xFactors: (CGFloat, CGFloat, CGFloat)let useHeight: (CGFloat, CGFloat, CGFloat)let yFactors: (CGFloat, CGFloat, CGFloat)}static let adjustment: CGFloat = 0.085static let points = [Segment(useWidth:  (1.00, 1.00, 1.00),xFactors:  (0.60, 0.40, 0.50),useHeight: (1.00, 1.00, 0.00),yFactors:  (0.05, 0.05, 0.00)),Segment(useWidth:  (1.00, 1.00, 0.00),xFactors:  (0.05, 0.00, 0.00),useHeight: (1.00, 1.00, 1.00),yFactors:  (0.20 + adjustment, 0.30 + adjustment, 0.25 + adjustment)),Segment(useWidth:  (1.00, 1.00, 0.00),xFactors:  (0.00, 0.05, 0.00),useHeight: (1.00, 1.00, 1.00),yFactors:  (0.70 - adjustment, 0.80 - adjustment, 0.75 - adjustment)),Segment(useWidth:  (1.00, 1.00, 1.00),xFactors:  (0.40, 0.60, 0.50),useHeight: (1.00, 1.00, 1.00),yFactors:  (0.95, 0.95, 1.00)),Segment(useWidth:  (1.00, 1.00, 1.00),xFactors:  (0.95, 1.00, 1.00),useHeight: (1.00, 1.00, 1.00),yFactors:  (0.80 - adjustment, 0.70 - adjustment, 0.75 - adjustment)),Segment(useWidth:  (1.00, 1.00, 1.00),xFactors:  (1.00, 0.95, 1.00),useHeight: (1.00, 1.00, 1.00),yFactors:  (0.30 + adjustment, 0.20 + adjustment, 0.25 + adjustment))]
}
  • 在 Badge.swift 文件中,绘制徽章的形状并使用fill修改器给六边形填充颜色,形成一个视图,使用路径可以把多条直线、曲线或其它绘制形状的基本笔划连成一个复杂的图形,就像形成徽章六边形背景这样:
struct Badge: View {var body: some View {Path{ (path) in}.fill(Color.black)}
}struct Badge_Previews: PreviewProvider {static var previews: some View {Badge()}
}
  • 给路径添加起点,move(to:)方法可以把绘图光标移动到绘图中的一点,准备绘制的起点:
struct Badge: View {var body: some View {Path{ (path) inlet width : CGFloat = 100let height = widthpath.move(to: CGPoint.init(x: width * 0.95, y: height * 0.20))}.fill(Color.black)}
}struct Badge_Previews: PreviewProvider {static var previews: some View {Badge()}
}
  • 使用六边形的绘制参数数据 HexagonParameters,依次绘制六边形的边,形成大致轮廓 .addLine(to:) 方法会使用当前绘图光标所在点为起点,方法参数中指定的点为终点绘制直线。目前六边形看起来有点问题,不过不要担心,这是意料中的事,下面的步骤做完,六边形的形状就会和开头显示的徽章的六边形形状一致了:

  • 使用 addQuadCurve(to:control:) 方法绘制贝塞尔曲线,让六边形的角变的更圆润些:

  • 把徽章路径包裹在一个 Geometry Reader 中,这样徽章可以使用容器的大小,定义自己绘制的尺寸,这样就不需要硬编码绘制尺寸了(100)。当绘制区域不是正方形时,使用绘制区域的最小边长(长宽中哪个最小使用哪个)作为绘制徽章背景的边长,并保持徽章背景的长宽比为1:1;

  • 使用 xScale 和 xOffset 参数调整变量,把徽章几何绘图区域居中绘制出来:

  • 把黑色实心填充色改为渐变色,使徽章看上去和开始设计的样式一致:

  • 渐变色上再使用 aspectRatio(_:contentMode:) 修改器,让渐变色按内容宽高比进行成比例渐变填充,保持 1:1 的长宽比,徽章背景可以保持居中在徽章视图中,不管徽章视图本身是不是正方形:

三、绘制徽章符号

  • 地标徽章中心有一个以地标 App 图标中的山峰图形改造形成的标志,山峰这个符号由两个形状组成,一个是表示山顶被雪覆盖的部分,另一个是山体。这里会使用有一定间距的两个局部三角形形状绘制这个徽章符号:

  • 把之前的徽章视图形状抽出来单独形成一个 BadgeBackground 视图,并生成一个新的视图文件BadgeBackground.swift:
struct BadgeBackground: View {var body: some View {GeometryReader{ geometry inPath{ (path) invar width : CGFloat = min(geometry.size.width, geometry.size.height)let height = widthlet xScale : CGFloat = 0.832let xOffset : CGFloat = (width * (1 - xScale)) / 2.0width *= xScalepath.move(to: CGPoint.init(x: xOffset + width * 0.95, y: height * (0.20 + HexagonParameters.adjustment)))HexagonParameters.points.forEach { segment inpath.addLine(to: CGPoint.init(x: xOffset + width * segment.useWidth.0 * segment.xFactors.0, y: height * segment.useHeight.0 * segment.yFactors.0))path.addQuadCurve(to: CGPoint.init(x: xOffset + width * segment.useWidth.1 * segment.xFactors.1, y: height * segment.useHeight.1 * segment.yFactors.1), control: CGPoint.init(x: xOffset + width * segment.useWidth.2 * segment.xFactors.2, y: height * segment.useHeight.2 * segment.yFactors.2))}}.fill(LinearGradient(gradient: Gradient(colors: [Self.gradientStart, Self.gradientEnd]), startPoint: UnitPoint.init(x: 0.5, y: 0), endPoint: UnitPoint.init(x: 0.5, y: 0.6))).aspectRatio(1, contentMode: .fit)}}static let gradientStart = Color(red: 239.0/255.0, green: 120.0/255.0, blue: 221.0/255.0)static let gradientEnd = Color(red: 239.0/255.0, green: 172.0/255.0, blue: 120.0/255.0)
}struct Badge_Previews: PreviewProvider {static var previews: some View {BadgeBackground()}
}
  • 把 BadgeBackground 放在 ContentView 的 body 属性中:

  • 创建名为 BadgeSymbol 的自定义视图,这个视图是一个山峰的形状,把这个形状复制多次并按一定角度旋转多次拼成一个徽章的图案:

  • 使用 pathAPI 来绘制徽章符号的上半部分,试着调节 spacing、topWidth、topHeight 的系数,观察这些系数是怎么影响图形绘制的结果的:

  • 绘制徽章图案的下半部分,使用 move(to:) 把绘图光标移到另一个图形绘制的起点,绘制新的形状:

  • 用紫色填充徽章符号:

四、组合徽章的前景符号和背景形状

  • 徽章设计思路是在背景形状上面再绘制多个有固定旋转角度的山峰符号。定义一个新的类型用于展示旋转一定角度的徽章符号,使用 ForEach 生成不同旋转角度的山峰符号,绘制在徽章背景上,从而形成最终的徽章。

  • 创建 RotatedBadgeSymbol 视图封装旋转徽章符号,调整旋转的角度,并在预览视图中查看效果:

  • 在 Badge.swift 中,使用 ZStack 把徽章图标放在徽章背景层上面。此时会发现,徽章符号的尺寸相比徽章背景大了许多,这不符合最初设计的预期:

  • 缩放符号尺寸到合适的大小:

  • 使用 ForEach 复制多个徽章图标,按 360 度周解均分,每一个徽章符号都比前一个多旋转 45 度,这种就会形成一个类似太阳和徽章图标:

五、完整示例

  • SwiftUI之绘制徽章视图的路径和形状。

SwiftUI之深入解析如何绘制徽章视图的路径和形状相关推荐

  1. SwiftUI之深入解析如何处理特定的数据和如何在视图中适配数据模型对象

    一.前言 阅读了我的前两篇博客的朋友,应该都熟练掌握了 SwiftUI 如何创建一个任何相关信息的展示视图和各个视图之间的相互组合,以及动态生成一个展示相关信息的可滚动列表,用户可以点击列表项去查看其 ...

  2. SwiftUI之深入解析如何创建列表展示视图和列表如何导航跳转新页面

    一.前言 地标详情页视图已经创建完成,我们需要提供一种方式让用户可以查看完整的地标列表,并且可以查看每一个地标的详情.地标详情页视图的创建,请参考我的博客:SwiftUI之深入解析如何创建和组合视图. ...

  3. SwiftUI WWDC21 新绘图和动画组件之 01 Canvas 支持即时模式绘制的视图类型

    SwiftUI WWDC21 新绘图和动画组件之 01 Canvas 支持即时模式绘制的视图类型 Canvas 一种支持即时模式绘制的视图类型. struct Canvas<Symbols> ...

  4. SwiftUI之深入解析高级动画的几何效果GeometryEffect

    一.前言 在我的博客 SwiftUI之深入解析高级动画的路径Paths 中,已经了解了 Animatable 的协议,以及如何使用它来动画路径.接下来,我们将使用相同的协议来动画变换矩阵,使用一个新的 ...

  5. iOS10 UI教程视图的绘制与视图控制器和视图

    iOS10 UI教程视图的绘制与视图控制器和视图 iOS10 UI视图的绘制 iOS10 UI教程视图的绘制与视图控制器和视图,在iOS中,有很多的绘图应用.这些应用大多是在UIView上进行绘制的. ...

  6. Android源码解析:UI绘制流程之控件绘制

    带着问题看源码 再接再厉,我们来分析UI绘制流程最后一步绘制流程 入口ViewRootImpl.performDraw()方法 private void performDraw() {//...try ...

  7. UWP 手绘视频创作工具技术分享系列 - 文字的解析和绘制

    本篇作为技术分享系列的第二篇,详细讲一下文字的解析和绘制,这部分功能的研究和最终实现由团队共同完成,目前还在寻找更理想的实现方式. 首先看一下文字绘制在手绘视频中的应用场景 文字是手绘视频中很重要的表 ...

  8. SwiftUI 中为什么应该经常用子视图替换父视图中的大段内容?

    概览 在 SwiftUI 官方教程中,Apple 时常提出"化整为零"的界面布局思想.简单来说,Apple 推荐 SwiftUI 视图的构建方式是:用若干自定义小视图来构成上层的功 ...

  9. 三维人体运动合成系列之一:运动捕捉数据ASF/AMC文件解析与绘制

    虚拟人运动合成是我研究生阶段的研究课题,目前我将已完成的工作整理出来,预计写三篇博客介绍,分为: 1.三维人体运动合成系列之一:运动捕捉数据ASF/AMC文件解析与绘制 2.三维人体运动合成系列之二: ...

最新文章

  1. 2019年春季学期第三周作业
  2. android上传视频 断点续传,断点续传上传
  3. 汇编语言 修改内存中的过时数据
  4. 在从1到n的正数中1出现的次数
  5. python 04 基础
  6. 推荐一个神器 - 把你的照片随心所欲的摆成各种形状
  7. 如何用 SQL 做留存率分析?
  8. 2021 测试工作年终总结
  9. CommonJS的值拷贝与ES6的动态映射
  10. spark学习之SparkSQL
  11. 【Android】上下文菜单ContextMenu的使用
  12. OpenCV 利用高斯模糊实现简单的磨皮美颜效果
  13. 牛客网-Java专项练习11
  14. 六、软件用户操作手册-模板
  15. docker+nginx+tomcat*3在华为云服务器上的负载均衡
  16. MATLAB图形加标注的基本方法入门简介
  17. Boundary Sensitive Network (BSN) 源码运行
  18. 使用 Leaflet.js 创建地图的入门指南
  19. python写软件实例-python写一个随机点名软件的实例
  20. 计算机类相关比赛(大学生版)

热门文章

  1. 微信改密码qq邮箱服务器繁忙,微信无法通过邮件修改密码,解决方法
  2. PTA(Basic Level) 1072:开学寄语(C语言实现)
  3. Kubernetes组件Ingress
  4. Ubuntu的快乐学习1——Ubuntu18.04的ROS平台搭建
  5. redis的多路复用
  6. python生成ppt报告_python 生成 pptx 分析报告的工具包:reportgen
  7. python地图匹配_坐标点地图匹配方法
  8. C语言自学保姆教程——第一节--编译准备与第一个C程序
  9. Palindrome Permutation
  10. C语言mum,Mum