SwiftUI启用具有两种不同类型的自定义绘图:路径和形状。路径是一系列绘制指令,例如“从此处开始,在此处绘制线,然后在此处添加圆”,所有指令均使用绝对坐标。相反,形状不知道将在何处使用或将使用多大的形状,而是会要求其在给定的矩形内绘制自身。
有用的是,形状是使用路径构建的,因此一旦您了解了路径,形状就很容易了。同样,就像路径,颜色和渐变一样,形状也是视图,这意味着我们可以将它们与文本视图,图像等一起使用。
SwiftUI使用一个必需的方法将Shape
作为协议实现:给定以下矩形,您想绘制什么路径?仍然会像直接使用原始路径一样创建并返回路径,但是由于我们已经掌握了大小,因此将使用形状,因为我们确切地知道绘制路径的大小——我们不再需要依赖固定的坐标。
例如,以前我们使用Path
创建了一个三角形,但是我们可以将其包装成一个形状以确保它自动占用所有可用空间,如下所示:
struct Triangle: Shape {
func path(in rect: CGRect) -> Path {
var path = Path()
path.move(to: CGPoint(x: rect.midX, y: rect.minY))
path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY))
path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
path.addLine(to: CGPoint(x: rect.midX, y: rect.minY))
return path
}
}
CGRect
使这项工作变得容易得多,它提供了有用的属性,例如minX
(矩形中最小的X值),maxX
(矩形中最大的X值)和midX
(minX
和maxX
之间的中点)。
然后,我们可以创建一个精确尺寸的红色三角形,如下所示:
Triangle()
.fill(Color.red)
.frame(width: 300, height: 300)
形状还支持相同的StrokeStyle
参数,以创建更多高级笔触:
Triangle()
.stroke(Color.red, style: StrokeStyle(lineWidth: 10, lineCap: .round, lineJoin: .round))
.frame(width: 300, height: 300)
理解Path
和Shape
之间差异的关键是可重用性:路径被设计为做一件特定的事情,而形状具有绘制空间的灵活性,并且还可以接受参数以使我们进一步自定义它们。
为了说明这一点,我们可以创建一个接受三个参数的圆弧(Arc
)形状:起始角度,结束角度以及是否顺时针绘制圆弧。这看起来似乎很简单,尤其是因为Path
具有addArc()
方法,但是如您所见,它具有几个有趣的现象。
让我们从最简单的弧形开始:
struct Arc: Shape {
var startAngle: Angle
var endAngle: Angle
var clockwise: Bool
func path(in rect: CGRect) -> Path {
var path = Path()
path.addArc(center: CGPoint(x: rect.midX, y: rect.midY), radius: rect.width / 2, startAngle: startAngle, endAngle: endAngle, clockwise: clockwise)
return path
}
}
我们现在可以像这样创建一个圆弧:
Arc(startAngle: .degrees(0), endAngle: .degrees(110), clockwise: true)
.stroke(Color.blue, lineWidth: 10)
.frame(width: 300, height: 300)
如果您查看我们弧线的预览,很可能它看起来不像您期望的那样。我们要求顺时针旋转的弧度是从0度到110度,但是我们似乎获得了逆时针旋转从90度到200度的圆弧。
这里发生了两件事:
- 在SwiftUI看来,0度不是笔直向上,而是直接向右。
- 形状是从左下角而不是左上角开始测量坐标的,这意味着SwiftUI从一个角度到另一个角度都以相反的方式进行测量。在我看来,这是非常陌生的。
我们可以使用新的path(in :)
方法解决这两个问题,该方法从起点和终点角度减去90度,并且还改变方向,以便SwiftUI遵循自然预期的方式:
func path(in rect: CGRect) -> Path {
let rotationAdjustment = Angle.degrees(90)
let modifiedStart = startAngle - rotationAdjustment
let modifiedEnd = endAngle - rotationAdjustment
var path = Path()
path.addArc(center: CGPoint(x: rect.midX, y: rect.midY), radius: rect.width / 2, startAngle: modifiedStart, endAngle: modifiedEnd, clockwise: !clockwise)
return path
}
运行该代码并查看您的想法——对我来说,它产生了一种更自然的工作方式,并巧妙地隔离了SwiftUI的古怪绘画行为。
译自 Paths vs shapes in SwiftUI
SwiftUI:创建自定义路径 Path | Hacking with iOS: SwiftUI Edition | SwiftUI:自定义 Shape 实现向内绘制边框 |
---|
赏我一个赞吧~~~