UIView.draw(rect:)调用未绘上下文:多进度条实例绘制异常
问题:自定义UIView多实例绘制异常,仅第一个显示圆弧
iOS开发新手,在自定义UIView(MyProgressView)的draw(rect:)方法中通过UIGraphicsGetCurrentContext绘制圆弧进度条,单个实例显示正常,但创建多个实例时,只有第一个能正确绘制,其余实例的draw(rect:)虽被调用却无图形输出。运行环境为iOS15.4的Playground。
自定义视图代码
class MyProgressView: UIView { var startAngle: Double = 0.0 var endAngle: Double = 0.0 { didSet{ self.setNeedsDisplay() } } func radian(_ degree: Double) -> Double { return (degree - 90) * Double.pi / 180.0 } override func draw(_ rect: CGRect) { guard let context = UIGraphicsGetCurrentContext() else { return } context.setLineWidth(10) context.setStrokeColor(UIColor.white.cgColor) context.addArc(center: self.center, radius: 30, startAngle: radian(startAngle), endAngle: radian(endAngle), clockwise: false) context.strokePath() } }
视图控制器viewDidLoad代码
let progressBar = MyProgressView() progressBar.frame = CGRect(x: 0, y: 0, width: view.frame.width / 2, height:view.frame.height / 2) progressBar.backgroundColor = .systemMint progressBar.startAngle = 0 progressBar.endAngle = 180 view.addSubview(progressBar) let progressBar2 = MyProgressView() progressBar2.frame = CGRect(x: 150, y: 0, width: view.frame.width / 2, height: view.frame.height / 2) progressBar2.backgroundColor = .systemPink progressBar2.startAngle = 90 progressBar2.endAngle = 270 view.addSubview(progressBar2) let progressBar3 = MyProgressView() progressBar3.frame = CGRect(x: 0, y: 150, width: view.frame.width / 2, height: view.frame.height / 2) progressBar3.backgroundColor = .systemIndigo progressBar3.startAngle = 90 progressBar3.endAngle = 270 view.addSubview(progressBar3)
问题原因
self.center是当前视图在父视图坐标系下的中心点坐标,而draw(rect:)方法的绘图上下文是基于当前视图自身的坐标系(原点在视图左上角,x轴向右,y轴向下)。
- 第一个视图的
frame是(0,0,w/2,h/2),它的center是(w/4, h/4),这个坐标在自身的rect范围内,所以圆弧能正常显示。 - 第二个视图的
frame是(150,0,w/2,h/2),它的center是(150 + w/4, h/4),但在自身绘图上下文里,x轴最大范围是w/2,这个center的x值远超出自身宽度,导致圆弧绘制在视图外部,自然看不到。 - 第三个视图同理,
center的y值超出自身高度范围,圆弧也绘制在视图外面。
解决方案
将圆弧的中心点改为当前视图自身rect的中心,也就是使用rect.midX和rect.midY构建坐标,而非self.center。
修改后的draw(rect:)方法代码:
override func draw(_ rect: CGRect) { guard let context = UIGraphicsGetCurrentContext() else { return } context.setLineWidth(10) context.setStrokeColor(UIColor.white.cgColor) // 使用当前视图自身rect的中心作为圆弧中心点 let center = CGPoint(x: rect.midX, y: rect.midY) context.addArc(center: center, radius: 30, startAngle: radian(startAngle), endAngle: radian(endAngle), clockwise: false) context.strokePath() }
内容的提问来源于stack exchange,提问作者Joon Mo Park
相关产品推荐
相关产品推荐

