GeometryReader 为您提供容器视图的信息,您可以获取geometry.size 之类的大小,然后计算中间点等
GeometryReader 内部的布局是 ZStack,所以所有项目都将是一个在彼此之上
绘制曲线的简单方法是Path { path in },在这个块内你可以添加线条/曲线到路径,而不是stoke()它
您可以通过两种方式绘制圆圈:第一种是再次使用Path,添加圆角矩形和fill()。
另一种选择是放置 Circle() 并添加偏移量
第一种方式是蓝色的,第二种方式是半径较小的绿色。我随机选择曲线控制点只是为了给你一个想法
let circleRelativeCenters = [
CGPoint(x: 0.8, y: 0.2),
CGPoint(x: 0.2, y: 0.5),
CGPoint(x: 0.8, y: 0.8),
]
var body: some View {
GeometryReader { geometry in
let normalizedCenters = circleRelativeCenters
.map { center in
CGPoint(
x: center.x * geometry.size.width,
y: center.y * geometry.size.height
)
}
Path { path in
var prevPoint = CGPoint(x: normalizedCenters[0].x / 4, y: normalizedCenters[0].y / 2)
path.move(to: prevPoint)
normalizedCenters.forEach { center in
path.addQuadCurve(
to: center,
control: .init(
x: (center.x + prevPoint.x) / 2,
y: (center.y - prevPoint.y) / 2)
)
prevPoint = center
}
}.stroke(lineWidth: 3).foregroundColor(.blue).background(Color.yellow)
Path { path in
let circleDiamter = geometry.size.width / 5
let circleFrameSize = CGSize(width: circleDiamter, height: circleDiamter)
let circleCornerSize = CGSize(width: circleDiamter / 2, height: circleDiamter / 2)
normalizedCenters.forEach { center in
path.addRoundedRect(
in: CGRect(
origin: CGPoint(
x: center.x - circleFrameSize.width / 2,
y: center.y - circleFrameSize.width / 2
), size: circleFrameSize
),
cornerSize: circleCornerSize
)
}
}.fill()
ForEach(normalizedCenters.indices, id: \.self) { i in
let center = normalizedCenters[i]
let circleDiamter = geometry.size.width / 6
let circleFrameSize = CGSize(width: circleDiamter, height: circleDiamter)
Circle()
.frame(size: circleFrameSize)
.offset(
x: center.x - circleFrameSize.width / 2,
y: center.y - circleFrameSize.width / 2
)
}.foregroundColor(.green)
}.frame(maxWidth: .infinity, maxHeight: .infinity).foregroundColor(.blue).background(Color.yellow)
}
结果:
在Path { path in 内部我可以使用forEach,因为它不再是视图构建器的范围。
如果你需要为你的修饰符做一些计算,你可以使用下一个技巧:
func circles(geometry: GeometryProxy) -> some View {
var points = [CGPoint]()
var prevPoint: CGPoint?
(0...5).forEach { i in
let point: CGPoint
if let prevPoint = prevPoint {
point = CGPoint(x: prevPoint.x + 1, y: prevPoint.y)
} else {
point = .zero
}
points.append(point)
prevPoint = point
}
return ForEach(points.indices, id: \.self) { i in
let point = points[i]
Circle()
.offset(
x: point.x,
y: point.y
)
}
}
然后你可以像circles(geometry: geometry).foregroundColor(.green)那样在body里面使用它