You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

视图尺寸变化时,是否仅能通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 05:16:10