在 SwiftUI 中,Path 结构体用于创建和组合图形。Path 提供了一系列方法来绘制线条和曲线,从而形成各种图形。下面是一些基本的方法:
move(to:): 将绘制的起始点移动到指定的位置。
addLine(to:): 从当前位置画一条直线到指定的位置。
addArc(center:radius:startAngle:endAngle:clockwise:): 添加一个圆弧。
addRect(_:): 添加一个矩形。
addEllipse(in:): 添加一个椭圆形。
addRoundedRect(in:cornerSize:): 添加一个带圆角的矩形。
addCurve(to:control1:control2:): 添加一个贝塞尔曲线。
addQuadCurve(to:control:): 添加一个二次贝塞尔曲线。
closeSubpath(): 关闭当前子路径,将绘制的终点与起始点连接。
下面是一个简单的例子,展示如何使用 Path 绘制一个三角形:
struct TriangleShape: View {
var body: some View {
Path { path in
path.move(to: CGPoint(x: 100, y: 100))
path.addLine(to: CGPoint(x: 200, y: 100))
path.addLine(to: CGPoint(x: 150, y: 200))
path.closeSubpath()
}
.stroke(Color.blue, lineWidth: 3)
}
}
要绘制组合图形,可以在同一个 Path 中绘制多个图形,或者使用多个 Path 并通过 ZStack 将它们叠加起来。下面是绘制一个组合图形(正方形内嵌圆形)的例子:
struct CombinedShape: View {
var body: some View {
Path { path in
// 正方形
let squareRect = CGRect(x: 50, y: 50, width: 200, height: 200)
path.addRect(squareRect)
// 圆形
let circleCenter = CGPoint(x: squareRect.midX, y: squareRect.midY)
path.addEllipse(in: CGRect(x: circleCenter.x - 50, y: circleCenter.y - 50, width: 100, height: 100))
}
.stroke(Color.green, lineWidth: 3)
}
}
你还可以使用 ZStack 将不同的 Path 组件重叠起来,创建复杂的组合图形:
struct StackedShapes: View {
var body: some View {
ZStack {
Path { path in
// 第一个图形(正方形)
let squareRect = CGRect(x: 50, y: 50, width: 200, height: 200)
path.addRect(squareRect)
}
.stroke(Color.red, lineWidth: 3)
Path { path in
// 第二个图形(圆形)
let circleCenter = CGPoint(x: 150, y: 150)
path.addEllipse(in: CGRect(x: circleCenter.x - 50, y: circleCenter.y - 50, width: 100, height: 100))
}
.stroke(Color.blue, lineWidth: 3)
}
}
}
要为使用 ZStack 组合的 Path 图形添加背景填充色,您可以使用 .fill() 修饰符来填充 Path。
struct StackedShapesFilled: View {
var body: some View {
ZStack {
// 正方形填充
Path { path in
let squareRect = CGRect(x: 50, y: 50, width: 200, height: 200)
path.addRect(squareRect)
}
.fill(Color.red.opacity(0.5)) // 半透明红色填充
// 圆形填充
Path { path in
let circleCenter = CGPoint(x: 150, y: 150)
path.addEllipse(in: CGRect(x: circleCenter.x - 50, y: circleCenter.y - 50, width: 100, height: 100))
}
.fill(Color.blue.opacity(0.5)) // 半透明蓝色填充
// 正方形轮廓
Path { path in
let squareRect = CGRect(x: 50, y: 50, width: 200, height: 200)
path.addRect(squareRect)
}
.stroke(Color.red, lineWidth: 3)
// 圆形轮廓
Path { path in
let circleCenter = CGPoint(x: 150, y: 150)
path.addEllipse(in: CGRect(x: circleCenter.x - 50, y: circleCenter.y - 50, width: 100, height: 100))
}
.stroke(Color.blue, lineWidth: 3)
}
}
}
用直线绘制一个矩形的三条边,然后最后一条边用圆形曲线去绘制,然后填充整个图形。
import SwiftUI
struct ArcRectangleView: View {
var body: some View {
Path { path in
// 定义矩形的起点
let startingPoint = CGPoint(x: 50, y: 50)
path.move(to: startingPoint)
// 绘制矩形的顶部边
path.addLine(to: CGPoint(x: 250, y: 50))
// 绘制矩形的右侧边
path.addLine(to: CGPoint(x: 250, y: 250))
// 绘制矩形的底部边(只绘制一部分,为了圆弧留出空间)
path.addLine(to: CGPoint(x: 50, y: 250))
// 添加圆形曲线作为最后一条边
// 圆心最右测为0度或360度,最左侧为180度,最下侧为90度,最上侧为270度或-90度
// clockwise true:逆时针绘制 false:顺时针绘制
path.addArc(center: CGPoint(x: 50, y: 150), radius: 100, startAngle: Angle(degrees: 90), endAngle: Angle(degrees: -90), clockwise: true)
// 回到起点闭合路径
path.addLine(to: startingPoint)
}
.fill(Color.blue) // 填充路径
}
}
struct ArcRectangleView_Previews: PreviewProvider {
static var previews: some View {
ArcRectangleView()
}
}
多个绘制几条曲线熟悉比较一下展示填充色和展示边框色的区别。
Path { path in
// 定义矩形的起点
let startingPoint = CGPoint(x: 50, y: 50)
path.move(to: startingPoint)
// 绘制矩形的顶部边
//path.addLine(to: CGPoint(x: 250, y: 50))
// 截掉右上角
path.addArc(center: CGPoint(x: 250, y: 50), radius: 50, startAngle: Angle(degrees: 180), endAngle: Angle(degrees: 90), clockwise: true)
// 绘制矩形的右侧边
path.addLine(to: CGPoint(x: 250, y: 250))
// 截掉右下角
path.addArc(center: CGPoint(x: 225, y: 225), radius: 25, startAngle: Angle(degrees: 0), endAngle: Angle(degrees: 90), clockwise: true)
// 绘制矩形的底部边(只绘制一部分,为了圆弧留出空间)
path.addLine(to: CGPoint(x: 50, y: 250))
// 添加圆形曲线作为最后一条边
// 圆心最右测为0度或360度,最左侧为180度,最下侧为90度,最上侧为270度或-90度
// clockwise true:逆时针绘制 false:顺时针绘制
path.addArc(center: CGPoint(x: 50, y: 150), radius: 100, startAngle: Angle(degrees: 90), endAngle: Angle(degrees: -90), clockwise: true)
// 回到起点闭合路径
path.addLine(to: startingPoint)
}
.fill(Color.blue) // 填充路径
//.stroke(Color.blue, lineWidth: 3) // 边框色
比如我们在正方形区域中减去圆形区域并透过圆形区域看到底层的内容
您需要使用 Path 的 even-odd 规则,这在图形学中被称为“非零缠绕数规则”。在 SwiftUI 中,您可以通过结合使用 .fill(_:style:) 方法和 FillStyle(eoFill: true) 来实现这一点。
struct CutoutShapeView: View {
var body: some View {
ZStack {
// 正方形与圆形结合的路径
Path { path in
// 定义正方形区域
let squareRect = CGRect(x: 50, y: 50, width: 200, height: 200)
path.addRect(squareRect)
// 定义圆形区域(这个圆形将从正方形区域中被减去)
let circleRect = CGRect(x: 150 - 50, y: 150 - 50, width: 100, height: 100)
path.addEllipse(in: circleRect)
}
.fill(Color.red.opacity(0.5), style: FillStyle(eoFill: true)) // 使用 even-odd 规则填充
// 可以添加其他视图或背景
// ... 例如一个背景图片或颜色
}
}
}
某区域被覆盖偶数层就镂空,被覆盖奇数层就会被遮挡。
这个功能很强大,可以用来为简单的图形取反,得到复杂的目标图形。
struct CutoutShapeView: View {
var body: some View {
ZStack {
// 正方形与圆形结合的路径
Path { path in
// 定义正方形区域
let squareRect = CGRect(x: 50, y: 50, width: 200, height: 200)
path.addRect(squareRect)
let squareRect1 = CGRect(x: 150, y: 150, width: 120, height: 120)
path.addRect(squareRect1)
// 定义圆形区域(这个圆形将从正方形区域中被减去)
let circleRect = CGRect(x: 150 - 50, y: 150 - 50, width: 100, height: 100)
path.addEllipse(in: circleRect)
}
.fill(Color.red.opacity(0.5), style: FillStyle(eoFill: true)) // 使用 even-odd 规则填充
// 可以添加其他视图或背景
// ... 例如一个背景图片或颜色
}
}
}