SwiftUI 中的自定义Shape

news2024/10/6 5:56:08

SwiftUI中,Shape协议允许开发者定义可重用的图形,这些图形可以用于绘制界面元素,如按钮、背景、边框等。通过实现 Shape 协议,可以创建完全自定义的图形,并控制其绘制方式。本文将详细介绍如何在 SwiftUI 中创建自定义 Shape,并提供几个示例。

Shape 协议基础

SwiftUI中,Shape是一个协议,要实现它,需要实现一个方法path(in rect: CGRect) -> Path。这个方法返回一个 Path 对象,该对象定义了图形的具体绘制路径。

绘制直线

绘制直线还是比较简单的,比如下面的代码,绘制了一个三角形。

struct Triangle: Shape {
  func path(in rect: CGRect) -> Path {
    Path { path in
      path.move(to: CGPoint(x: rect.midX, y: rect.minY))
      path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
      path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY))
      path.closeSubpath()
    }
  }
}

在这里插入图片描述
在绘制开始时,先调用move方法定位起始点,然后通过addLine方法,并传入下一点的信息,绘制直线,最后闭合整个绘制路径即可。

下面绘制一个复杂点的,五角星。

struct StarShape: Shape {
  func path(in rect: CGRect) -> Path {
    let h = Double(min(rect.size.width, rect.size.height)) // 确保星形保持正方形区域内
    let c = CGPoint(x: rect.size.width / 2, y: rect.size.height / 2) // 中心点
    let r = h / 2.0 // 外圈半径
    let angle = Double.pi * 2 / 5 // 每个星角的角度

    var path = Path()

    // 计算五个外圈顶点
    let points: [CGPoint] = (0..<5).map { i in
      let adjustedAngle = angle * Double(i) - Double.pi / 2
      return CGPoint(x: c.x + r * cos(adjustedAngle), y: c.y + r * sin(adjustedAngle))
    }

    // 计算五个内圈顶点
    let r2 = r * sin(angle / 2) / (1 + sin(angle / 2)) // 内圈半径
    var innerPoints: [CGPoint] = []
    for i in 0..<5 {
        let adjustedAngle = angle * Double(i) - Double.pi / 2 + angle / 2
        let point = CGPoint(x: c.x + r2 * cos(adjustedAngle), y: c.y + r2 * sin(adjustedAngle))
        innerPoints.append(point)
    }

    // 绘制星形
    path.move(to: points[0])
    for i in 0..<5 {
      path.addLine(to: innerPoints[i])
      path.addLine(to: points[(i + 1) % 5])
    }
    path.closeSubpath()

    return path
  }
}

在这里插入图片描述

绘制圆弧

圆弧可以通过 PathaddArc 方法来绘制。这个方法需要几个参数:圆心(center)、半径(radius)、起始角度(startAngle)、结束角度(endAngle)以及是否顺时针(clockwise)。
上面的参数都比较好理解,角度是从圆的正东方向开始测量的。这里特别说一个clockwise是否顺时针参数。
clockwise参数决定了创建圆弧的方向,最终路径的实际方向取决于转换参数和绘制路径的上下文的当前转换。然而,因为SwiftUI默认使用一个垂直翻转的坐标系(原点在视图的左上角),指定一个顺时针的弧线在应用转换后会导致一个逆时针的弧线。

比如下面的示例,clockwise为false,逆时针绘制,而弧线是从右侧画到左侧的,顺时针绘制的,如果将沿着X轴将Y轴上下翻转,再看就是逆时针绘制了,这也和我们传的参数值对上了。

struct ArcShape: Shape {
  func path(in rect: CGRect) -> Path {
    var path = Path()
    path.addArc(center: CGPoint(x: rect.midX, y: rect.midY),
                radius: rect.width / 2,
                startAngle: .degrees(0),
                endAngle: .degrees(180),
                clockwise: false)
    return path
  }
}

在这里插入图片描述

绘制贝塞尔曲线

二次贝塞尔曲线

SwiftUI 中,Path类提供了addQuadCurve(to:control:) 方法,这是用于绘制二次贝塞尔曲线的工具。二次贝塞尔曲线是一种使用单个控制点来定义曲线形状的方法,它可以创建平滑的曲线,常用于图形设计和动画中。

addQuadCurve(to:control:) 方法接受两个参数:
to: CGPoint 类型,表示曲线的终点。
control: CGPoint 类型,表示控制点,这个点决定了曲线的弯曲程度和方向。

二次贝塞尔曲线基于线性插值。给定一个起点(当前路径的最后一个点),一个终点(to 参数),和一个控制点(control 参数),曲线在起点和终点之间插值,控制点则决定曲线的弯曲程度和方向。

struct QuadCurveShape: Shape {
  func path(in rect: CGRect) -> Path {
    var path = Path()
    // 设置起点
    path.move(to: CGPoint(x: rect.minX, y: rect.midY))

    // 添加二次贝塞尔曲线
    path.addQuadCurve(to: CGPoint(x: rect.maxX, y: rect.midY),
                      control: CGPoint(x: rect.midX, y: rect.minY))
    return path
  }
}

我们首先使用 move(to:) 方法设置曲线的起点。
然后,使用 addQuadCurve(to:control:) 方法添加一条二次贝塞尔曲线。曲线的终点设置在矩形的最右侧中点,控制点设置在矩形的顶部中点。这样,曲线从左侧中点开始,向上弯曲到顶部中点,然后再向下弯曲到右侧中点。
在这里插入图片描述

三次贝塞尔曲线

Path 类提供了 addCurve(to:control1:control2:) 方法,用于绘制三次贝塞尔曲线。三次贝塞尔曲线比二次贝塞尔曲线提供更高的控制精度,因为它使用两个控制点而不是一个,允许创建更复杂的曲线形状。

addCurve(to:control1:control2:) 方法接受三个参数:
to: CGPoint 类型,表示曲线的终点。
control1: CGPoint 类型,表示第一个控制点,这个点主要影响曲线的起始部分。
control2: CGPoint 类型,表示第二个控制点,这个点主要影响曲线的结束部分。

三次贝塞尔曲线通过两个控制点来定义曲线的形状。起点和终点(to 参数)定义了曲线的起始和结束位置,而两个控制点(control1 和 control2)则共同决定了曲线的整体弯曲路径。

struct CurveShape: Shape {
  func path(in rect: CGRect) -> Path {
    var path = Path()
    path.move(to: CGPoint(x: rect.minX, y: rect.midY))
    path.addCurve(to: CGPoint(x: rect.maxX, y: rect.midY),
                  control1: CGPoint(x: rect.minX + rect.width / 3, y: rect.minY),
                  control2: CGPoint(x: rect.maxX - rect.width / 3, y: rect.maxY))
    return path
  }
}

我们首先使用 move(to:) 方法设置曲线的起点。
然后,使用 addCurve(to:control1:control2:) 方法添加一条三次贝塞尔曲线。曲线的终点设置在矩形的最右侧中点,第一个控制点设置在矩形的左侧三分之一处的顶部,第二个控制点设置在矩形的右侧三分之一处的底部。这样,曲线从左侧中点开始,先向上弯曲到第一个控制点,然后向下弯曲到第二个控制点,最后平滑过渡到右侧中点。
在这里插入图片描述
下面这个图是关于二次和三次贝塞尔曲线的示意图:
在这里插入图片描述

写在最后

本文主要介绍了常用的一些自定义图形,绘制直线,弧线,以及曲线,感兴趣的朋友还可以将这些组合起来使用,绘制符合App设计的图形。

最后,希望能够帮助到有需要的朋友,如果觉得有帮助,还望点个赞,添加个关注,笔者也会不断地努力,写出更多更好用的文章。

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

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

相关文章

Qt-Advanced-Docking-System的学习

Qt-Advanced-Docking-System使用说明_cdockmanager-CSDN博客 示例1&#xff1a; #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow> #include "DockManager.h" #include "QtDock/DockAreaWidget.h" namespace Ui { class MainWind…

计算机组成原理之运算方法和运算器

文章目录 数据与文字的表示方法定点表示法机器码&#xff08;机器数&#xff09;原码 反码补码移码 浮点表示法尾数规格化 数据与文字的表示方法 定点表示法 机器码&#xff08;机器数&#xff09; 正数的原码、反码、补码一样&#xff0c;负数的原码、反码、补码的符号位均为…

迅狐矩阵系统:智能化多平台内容管理与发布

迅狐矩阵系统是一套专为提高数字内容管理和发布效率而设计的综合性解决方案。它通过一系列智能化功能&#xff0c;帮助用户实现多平台内容的高效管理和发布&#xff0c;以下是系统的几大核心优势&#xff1a; 多平台绑定发布 迅狐矩阵系统支持用户绑定多个平台的多个账号&…

linux驱动学习(十一)之内核时钟

需要板子一起学习的可以这里购买&#xff08;含资料&#xff09;&#xff1a;点击跳转 一、内核时钟 1、内核时钟 内核时钟&#xff08;Kernel Clock&#xff09;&#xff0c;也称为系统时钟&#xff08;System Clock&#xff09;或滴答时钟&#xff08;Tick Timer&#xff0…

使用LANGCHAIN和GEMINI构建AI应用程序

借助这些先进技术&#xff0c;您可以生成文本、分析图像并实现多模态 AI 交互。 LangChain 和 Google 的 Gemini API 是什么&#xff1f; LangChain&#xff1a;构建 AI 应用程序的弹性框架 LangChain 是一个强大且灵活的框架&#xff0c;可以简化 AI 应用程序的开发。它提供…

绝对新惊喜:4款王者级别的办公软件,免费又实用

工作里有那么多规矩&#xff0c;但效率绝对是重中之重&#xff0c;选对了好软件&#xff0c;工作就能更高效&#xff0c;下班也能更早回家。 要是你也想做个“时间管理小能手”&#xff0c;下面这4款超好用的办公软件&#xff0c;你可千万别错过&#xff01; Gitmind 现在很…

奇绩创坛 2024 年春季创业营路演

奇绩创坛 2024 年春季创业营路演 奇绩创坛在北京中关村举办的 2024 年春季创业营路演 奇绩创坛在北京中关村举办的 2024 年春季创业营路演 RWKV 元始智能的COO罗璇在会议上详细分享了RWKV的创新模型架构、最新进展以及当前的研究方向。 目前&#xff0c;RWKV架构已经推出了最…

五、LVS原理

目录 5.1 LVS 相关原理 5.1.1 LVS集群的体系结构以及特点 5.1.1.1 LVS简介 5.1.1.2 LVS体系结构 5.1.1.3 LVS相关术语 5.1.1.4 LVS工作模式 5.1.1.5 LVS调度算法 5.1.2 LVS-DR集群介绍 5.1.2.1 LVS-DR模式工作原理 5.1.2.2 LVS-DR模式应用特点 5.1.2.3 LVS-DR模式ARP抑制 5.1…

使用Transformer进行抄袭检测

动机 在许多行业中&#xff0c;尤其是在学术界&#xff0c;抄袭是一个重大问题。随着互联网和开放信息的兴起&#xff0c;这种现象甚至变得更加严重&#xff0c;任何人都可以通过点击访问特定主题的任何信息。 基于这一观察&#xff0c;研究人员一直在尝试使用不同的文本分析…

生成高保真度3D数字人化身:打造你的专属虚拟形象

在数字化时代,我们的虚拟形象正变得越来越重要。现在,一项前沿技术正将这一领域推向新的高度——生成高保真度的3D数字人化身。这项技术不仅可以将你的形象以3D形式呈现,更能赋予它生命,让你的虚拟形象拥有丰富的表情和动作。 一、技术简介 这项技术就像是一个高级的3D照…

最简单的方法,连续打印多个空格

1、大家都知道&#xff0c;c语言中&#xff0c;我们打印语句时&#xff0c;如果使用\t来控制打印间隔&#xff0c;可能会出现排版错乱问题&#xff0c;所以一般都会使用空格来控制间隔&#xff0c;这样不管在哪个工具上面显示&#xff0c;打印的信息都不会错乱。 2、控制间隔的…

fdtd(时域有限差分)仿真

FDTD Solutions 是一款非常好用的微纳光学设计工具。该软件提供了丰富的设计功能&#xff0c;支持 CMOS 图像传感器&#xff0c;OLED 和液晶&#xff0c;表面计量&#xff0c;表面等离子体&#xff0c;石墨烯&#xff0c;太阳能电池&#xff0c;集成光子组件&#xff0c;超材 料…

Offline :Adversarially Trained Actor Critic for Offline Reinforcement Learning

ICML 2022 paper code 基于Stackelberg游戏博弈形式&#xff0c;对抗的学习actor与critic Intro Method 将离线RL的Stackelberg博弈表述为一个双层优化问题&#xff0c;学习者策略π∈Π为领导者&#xff0c;批评家f∈F为跟随者: π ^ ∗ ∈ argmax ⁡ π ∈ I I L μ ( π…

JVM如何确定方法调用

方法调用并不等同于方法执行&#xff0c;方法调用阶段唯一的任务就是确定调用哪一个方法&#xff0c;不涉及方法内部的具体运行过程。在程序运行时&#xff0c;进行方法调用是最普遍、最频繁的操作&#xff0c;但Class文件的编译过程中不包含传统编译中的连接步骤&#xff0c;一…

破解动态网页:如何用JavaScript获取自动消失的联想词

前几天在做数据分析时&#xff0c;我尝试获取某网站上输入搜索词后的联想词&#xff0c;输入搜索词后会弹出一个显示联想词的框。有趣的是&#xff0c;当我尝试通过按F12定位这个弹框在HTML中的位置时&#xff0c;输入框失去焦点后&#xff0c;联想词弹框就自动消失了。我观察到…

UnityAPI学习之Animator的基本使用

动画与动画控制器 示例1&#xff1a; 创建Animator对动画控制器进行统一管理&#xff0c;在Gris中创建Animator组件&#xff0c;并对其中的Controller属性进行赋值 在进行动画创作前&#xff0c;需先将图片的Texture Type属性改为Sprite(2D and UI) 再将一系列图片拖入Gris物…

nss刷题(4)

1、[SWPUCTF 2021 新生赛]easyrce <?php error_reporting(0); highlight_file(__FILE__); if(isset($_GET[url])) { eval($_GET[url]); } ?> if(isset($_GET[url])) isset函数用来检测url变量是否存在&#xff1b;$_GET函数获取变量数据 eval($_GET[url]); eval函数用…

基于Java+Swing+mysql幼儿园信息管理系统V2

博主介绍&#xff1a; 大家好&#xff0c;本人精通Java、Python、C#、C、C编程语言&#xff0c;同时也熟练掌握微信小程序、Php和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我有丰富的成品Java、Python、C#毕设项目经验&#xff0c;能够为学生提供各类…

和鲸101领航北中医:助力健康医疗AI实验室建设,培养交叉数据人才

2024 年 3 月开学季&#xff0c;北京中医药大学&#xff08;简称“北中医”&#xff09;的健康医疗人工智能实验室迎来了正式投入使用后的第一堂课。除了配备全新的桌椅和尖端的硬件服务器外&#xff0c;实验室还引入了先进的人工智能实训平台&#xff0c;为大数据管理与应用专…

Linux1(介绍与基本命令)

目录 一、初始Linux 1. Linux的起源 2. Linux是什么&#xff1f; 3. Linux内核版本 4. Linux的应用 5. 终端 6. Shell 7. Linux目录结构 二、基本命令 1. 基本的命令格式 2. shutdown 关机命令 3. pwd 当前工作目录 4. ls 查看目录内容 5. cd 改变工作目录 …