在UIKit中的图形绘制大多都是基于Quartz2D的,它的API使用起来较为繁琐,使用不当时还会导致性能问题。SwiftUI在这方面做了改进,使得绘制图形变成一件简单的事情。
通过几个例子来了解一下常用API,其中包括,基础图形,直线,曲线。
基础图形
使用方法很简单,初始化一个Rectangle,在添加一个frame修饰符,在添加一个fill修饰符用于填充颜色即可。为了达到演示的效果,我们稍微丰富一下,使用几个额外的修饰符,代码如下:
GeometryReader { geometry in
ZStack {
ForEach(0..<3) { i in
Rectangle()
.fill(
LinearGradient(gradient: .init(colors: [.green, .blue]), startPoint: .init(x: 0, y: 1), endPoint: .init(x: 1, y: 0))
)
.frame(width: geometry.size.width * 0.7, height: geometry.size.width * 0.7)
.rotationEffect(.degrees(Double(i) * 60))
}
Image("baymax-white")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: geometry.size.width * 0.5)
}
}
效果图如下所示:
rectangle.png
其中,fill
可以传入一个颜色,或如示例中的渐变色;ForEach
可以遍历生成一组view,在示例中生成了三个矩形,每个矩形根据当前index和rotationEffect
旋转一定的角度。比较特别的是一个容器对象GeometryReader
,通过这个容器,可以得到容器内部元素的size。其他的形状如:Circle,Ellipse,Rounded Rectangle,Capsule可以如法炮制。
Path
- 直线
当内建的形状不能满足需求时,可以使用Path来自己绘制一个图形,示例代码中通过Path绘制了一个简单的梯形:
Path { path in
path.move(to: CGPoint(x: 120, y: 20))
path.addLine(to: CGPoint(x: 180, y: 180))
path.addLine(to: CGPoint(x: 20, y: 180))
path.addLine(to: CGPoint(x: 80, y: 20))
}
看一个稍微复杂一点的实例:
GeometryReader { geometry in
ZStack {
Path { path in
let size = min(geometry.size.width, geometry.size.height)
let nearLine = size * 0.1
let farLine = size * 0.9
path.move(to: CGPoint(x: size / 2 + nearLine, y: nearLine))
path.addLine(to: CGPoint(x: farLine, y: farLine))
path.addLine(to: CGPoint(x: nearLine, y: farLine))
path.addLine(to: CGPoint(x: size / 2 - nearLine, y: nearLine))
}
.fill(Color.init(red: 0.4, green: 0.4, blue: 0.4))
Path { path in
let size = min(geometry.size.width, geometry.size.height)
let nearLine = size * 0.1
let farLine = size * 0.9
let middle = size / 2
path.move(to: .init(x: middle, y: farLine))
path.addLine(to: .init(x: middle, y: nearLine))
}
.stroke(Color.white, style: .init(lineWidth: 3.0, dash: [geometry.size.width / 20, geometry.size.width / 30], dashPhase: 0))
Image(systemName: "car.fill")
.resizable()
.frame(width: geometry.size.width / 4, height: geometry.size.width / 4)
.foregroundColor(Color.white)
.offset(x: -geometry.size.width / 6.72, y: -geometry.size.width / 2.75)
}
}
示例代码的效果图如下所示:
path.png
- 曲线
绘制曲线同样使用Path,不同的是将addLine
改为addQuadCurve
,在addQuadCurve
中除了指定终点外,还需要一个control point,示例代码如下所示:
GeometryReader { geometry in
HStack {
Path { path in
let size = min(geometry.size.width, geometry.size.height)
let nearLine = size * 0.1
let farLine = size * 0.9
let mid = size / 2
path.move(to: .init(x: mid, y: nearLine))
path.addQuadCurve(to: .init(x: farLine, y: mid), control: .init(x: size, y: 0))
path.addQuadCurve(to: .init(x: mid, y: farLine), control: .init(x: size, y: size))
path.addQuadCurve(to: .init(x: nearLine, y: mid), control: .init(x: 0, y: size))
path.addQuadCurve(to: .init(x: mid, y: nearLine), control: .init(x: 0, y: 0))
}
.fill(Color.yellow)
}
}
绘制的结果如下图所示:
curv.png
题外话
当使用Image元素时,会发现它不受frame修饰符的控制,在屏幕上始终显示图片的原始大小。若希望将它约束在frame所指定的范围内时,需要添加resizable
修饰符,此时它的长宽比例将随frame的宽高改变,呈现一个stretch状态。若想继续保留原有比例,则需要另一个修饰符aspectRatio
。
网友评论