Core Graphics
问题
Core Graphics 怎么用?draw(_:) 和 drawRect 的工作原理?
答案
自定义绘制
class ChartView: UIView {
override func draw(_ rect: CGRect) {
guard let context = UIGraphicsGetCurrentContext() else { return }
// 绘制背景
context.setFillColor(UIColor.white.cgColor)
context.fill(rect)
// 绘制折线
context.setStrokeColor(UIColor.blue.cgColor)
context.setLineWidth(2.0)
context.move(to: CGPoint(x: 20, y: 100))
context.addLine(to: CGPoint(x: 80, y: 50))
context.addLine(to: CGPoint(x: 140, y: 80))
context.strokePath()
// 绘制圆
let circleRect = CGRect(x: 50, y: 50, width: 60, height: 60)
context.setFillColor(UIColor.red.withAlphaComponent(0.3).cgColor)
context.fillEllipse(in: circleRect)
}
}
UIBezierPath
// 更高层 API,封装 CGPath
let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: 100))
path.addCurve(
to: CGPoint(x: 200, y: 100),
controlPoint1: CGPoint(x: 50, y: 0),
controlPoint2: CGPoint(x: 150, y: 200)
)
let shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath
shapeLayer.strokeColor = UIColor.blue.cgColor
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.lineWidth = 2.0
view.layer.addSublayer(shapeLayer)
异步绘制
// 主线程绘制可能卡顿,使用异步绘制
DispatchQueue.global().async {
UIGraphicsBeginImageContextWithOptions(size, false, 0)
// ... 复杂绘制
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
DispatchQueue.main.async {
imageView.image = image
}
}
常见面试问题
Q1: setNeedsDisplay 和 setNeedsLayout 的区别?
答案:
setNeedsDisplay:标记需要重绘,下次 RunLoop 调用draw(_:)setNeedsLayout:标记需要重新布局,下次 RunLoop 调用layoutSubviews()