就在不久之前,我甚至不知道贝塞尔曲线的发音,更不用说知道如何使用贝塞尔曲线路径来定制形状了.以下是我所学到的.事实证明,他们并不像一开始看起来那么可怕.
How to draw a Bézier path in a custom view
以下是主要步骤:
- 设计所需形状的轮廓.
- 将轮廓路径分割为直线段、圆弧段和曲线段.
- 以编程方式构建该路径.
- 使用
drawRect
或CAShapeLayer
绘制路径.
Design shape outline
你可以做任何事情,但作为一个例子,我 Select 了下面的形状.它可能是键盘上的一个弹出键.
Divide the path into segments
回顾您的形状设计,将其分解为更简单的直线元素(对于直线)、圆弧元素(对于圆和圆角元素)和曲线元素(对于其他元素).
下面是我们的示例设计:
个
- 黑色是线段
- 浅蓝色是圆弧段
- 红色是曲线
- 橙色圆点是曲线的控制点
- 绿点是路径段之间的点
- 虚线显示边框
- 深蓝色数字是按它们将以编程方式添加的顺序排列的线段
Build the path programmatically
我们将任意从左下角开始,顺时针方向工作.我将使用图像中的网格来获取点的x和y值.我将在这里对所有内容进行硬编码,但在真正的项目中当然不会这样做.
基本流程是:
- 创建一个新的
UIBezierPath
- 用
moveToPoint
Select 路径上的起点
- Add segments to the path
- 电话:
addLineToPoint
- 弧度:
addArcWithCenter
- 曲线:
addCurveToPoint
- 用
closePath
结束路径
下面是在上图中创建路径的代码.
func createBezierPath() -> UIBezierPath {
// create a new path
let path = UIBezierPath()
// starting point for the path (bottom left)
path.move(to: CGPoint(x: 2, y: 26))
// *********************
// ***** Left side *****
// *********************
// segment 1: line
path.addLine(to: CGPoint(x: 2, y: 15))
// segment 2: curve
path.addCurve(to: CGPoint(x: 0, y: 12), // ending point
controlPoint1: CGPoint(x: 2, y: 14),
controlPoint2: CGPoint(x: 0, y: 14))
// segment 3: line
path.addLine(to: CGPoint(x: 0, y: 2))
// *********************
// ****** Top side *****
// *********************
// segment 4: arc
path.addArc(withCenter: CGPoint(x: 2, y: 2), // center point of circle
radius: 2, // this will make it meet our path line
startAngle: CGFloat(M_PI), // π radians = 180 degrees = straight left
endAngle: CGFloat(3*M_PI_2), // 3π/2 radians = 270 degrees = straight up
clockwise: true) // startAngle to endAngle goes in a clockwise direction
// segment 5: line
path.addLine(to: CGPoint(x: 8, y: 0))
// segment 6: arc
path.addArc(withCenter: CGPoint(x: 8, y: 2),
radius: 2,
startAngle: CGFloat(3*M_PI_2), // straight up
endAngle: CGFloat(0), // 0 radians = straight right
clockwise: true)
// *********************
// ***** Right side ****
// *********************
// segment 7: line
path.addLine(to: CGPoint(x: 10, y: 12))
// segment 8: curve
path.addCurve(to: CGPoint(x: 8, y: 15), // ending point
controlPoint1: CGPoint(x: 10, y: 14),
controlPoint2: CGPoint(x: 8, y: 14))
// segment 9: line
path.addLine(to: CGPoint(x: 8, y: 26))
// *********************
// **** Bottom side ****
// *********************
// segment 10: line
path.close() // draws the final line to close the path
return path
}
注意:通过在单个命令中添加一条直线和一条圆弧(因为圆弧有一个隐含的起点),可以减少上面的一些代码.有关更多详细信息,请参见here.
Draw the path
我们可以在图层中绘制路径,也可以在drawRect
中绘制路径.
Method 1: Draw path in a layer个
我们的自定义类如下所示.当视图初始化时,我们将Bezier路径添加到新的CAShapeLayer
.
import UIKit
class MyCustomView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
func setup() {
// Create a CAShapeLayer
let shapeLayer = CAShapeLayer()
// The Bezier path that we made needs to be converted to
// a CGPath before it can be used on a layer.
shapeLayer.path = createBezierPath().cgPath
// apply other properties related to the path
shapeLayer.strokeColor = UIColor.blue.cgColor
shapeLayer.fillColor = UIColor.white.cgColor
shapeLayer.lineWidth = 1.0
shapeLayer.position = CGPoint(x: 10, y: 10)
// add the new layer to our custom view
self.layer.addSublayer(shapeLayer)
}
func createBezierPath() -> UIBezierPath {
// see previous code for creating the Bezier path
}
}
在视图控制器中创建视图,如下所示
override func viewDidLoad() {
super.viewDidLoad()
// create a new UIView and add it to the view controller
let myView = MyCustomView()
myView.frame = CGRect(x: 100, y: 100, width: 50, height: 50)
myView.backgroundColor = UIColor.yellow
view.addSubview(myView)
}
我们得到了...
个
嗯,那有点小,因为我把所有的数字都硬编码进go 了.不过,我可以将路径大小放大,如下所示:
let path = createBezierPath()
let scale = CGAffineTransform(scaleX: 2, y: 2)
path.apply(scale)
shapeLayer.path = path.cgPath
个
Method 2: Draw path in 100
使用draw
比绘制到图层慢,因此如果您不需要此方法,则不推荐使用此方法.
以下是我们的自定义视图的修订代码:
import UIKit
class MyCustomView: UIView {
override func draw(_ rect: CGRect) {
// create path (see previous code)
let path = createBezierPath()
// fill
let fillColor = UIColor.white
fillColor.setFill()
// stroke
path.lineWidth = 1.0
let strokeColor = UIColor.blue
strokeColor.setStroke()
// Move the path to a new location
path.apply(CGAffineTransform(translationX: 10, y: 10))
// fill and stroke the path (always do these last)
path.fill()
path.stroke()
}
func createBezierPath() -> UIBezierPath {
// see previous code for creating the Bezier path
}
}
这给了我们同样的结果.
个
Further study
我really推荐看以下material .正是它们最终让我可以理解贝塞尔曲线的道路.(并教我如何发音:/ˈbɛzi eɪ/.)