视图尺寸变化时,是否仅能通过layoutSubviews调用setNeedsDisplay触发draw#rect重绘?
视图尺寸变化时
draw(_:)重绘的更优实现方式 问题场景
在自定义视图的draw(_ rect: CGRect)方法中绘制固定坐标的线条,示例代码如下:
override func draw(_ rect: CGRect) { guard let c = UIGraphicsGetCurrentContext() else { return } c.move(to: CGPoint(x: 13, y: 13 ) ) c.addLine(to: CGPoint(x: 69, y: 69 ) ) c.setLineWidth(1.0 / UIScreen.main.scale) // 其他绘制逻辑 }
当用户通过捏合等操作改变视图尺寸(比如从100×100变为300×300)时,根图层上的绘制线条会被系统缩放,导致线条变粗、模糊;但通过约束添加的文本、图层形状等元素会自动进行逻辑缩放,不会出现这类问题。
当前解决方案
为了让draw(_:)在视图尺寸变化时持续重绘,目前的实现是在layoutSubviews()中调用setNeedsDisplay():
override func layoutSubviews() { super.layoutSubviews() setNeedsDisplay() someOtherStuff.path = calculation().cgPath someLabel.text = String(bounds.width / 13) }
该方式可以正常工作,但存在疑问:是否有更优、更简洁的内置实现方式?比如专门的回调方法或视图标记(类似clearsContextBeforeDrawing的属性)。
回答
没有比在layoutSubviews中调用setNeedsDisplay更简洁的内置方案。
UIKit的默认逻辑是,draw(_:)仅在视图首次显示、手动调用setNeedsDisplay,或视图内容被标记为"脏"时才触发重绘。视图尺寸变化本身不会自动触发draw(_:)重绘,因为系统默认假设你可能希望直接缩放已有绘制内容,而非重新绘制。
目前不存在专门的视图属性可以开启"尺寸变化自动重绘draw(_:)"的功能,也没有专门的回调方法直接对应这个场景。
不过你可以对当前实现做一点优化:只在bounds真正发生变化时才执行重绘和相关逻辑,避免不必要的重复操作:
private var lastRecordedBounds: CGRect = .zero override func layoutSubviews() { super.layoutSubviews() guard bounds != lastRecordedBounds else { return } lastRecordedBounds = bounds setNeedsDisplay() someOtherStuff.path = calculation().cgPath someLabel.text = String(bounds.width / 13) }
内容的提问来源于stack exchange,提问作者Fattie
相关产品推荐
相关产品推荐

