通过Storyboard运行时属性设置UIView圆角出现2-3秒延迟,求原因
为什么通过Storyboard运行时属性设置圆角会延迟显示?
嘿,这个问题我之前做Demo的时候也碰到过,其实根源在UIKit的初始化、布局和渲染的先后顺序上,我给你掰扯清楚:
- 运行时属性的设置太早了:你在Storyboard里加的用户定义运行时属性,是在视图执行
init(coder:)初始化的时候就被赋值的。但这时候Auto Layout还没开始干活呢——哪怕你给视图绑死了leading、trailing、bottom和高度约束,视图的真实尺寸(也就是bounds)要等到layoutSubviews方法调用后才会确定。 - 圆角吃视图尺寸的“饭”:
cornerRadius的渲染完全依赖视图当前的bounds。如果在init(coder:)阶段就设置圆角,此时视图用的还是Storyboard里的占位尺寸(不是最终布局后的真实大小),这时候设置的圆角要么没效果(比如你设了高度一半的圆角,但占位高度很小),要么系统得等布局完成后重新计算渲染,这个重新计算的过程就造成了你看到的2-3秒延迟。 - UIKit的性能优化“帮倒忙”:UIKit为了省性能,会把非紧急的渲染操作往后拖。当视图尺寸因为Auto Layout发生变化后,系统会标记视图需要重绘,但这个重绘不是立刻执行的,得等下一个渲染周期,这就加剧了延迟感。
另外提个容易漏的点:如果没给视图开masksToBounds = true,圆角也可能出问题,但你这里是延迟显示,主要还是上面的时机问题。
怎么解决这个延迟问题?
给你几个靠谱的方案,随便选一个都能搞定:
方案1:代码里在布局完成后设置圆角
写个自定义UIView子类,在layoutSubviews里设置圆角——这个方法每次布局完成(尺寸确定)都会调用,能保证圆角立刻生效:class RoundedView: UIView { override func layoutSubviews() { super.layoutSubviews() // 这里可以设固定值,比如16,也可以用高度一半做全圆角 layer.cornerRadius = bounds.height / 2 layer.masksToBounds = true } }然后去Storyboard里把你的视图类改成这个自定义类,删掉之前的用户定义运行时属性就行。
方案2:在Storyboard里补上
masksToBounds属性
要是你非得用运行时属性,那除了cornerRadius,再加一个用户定义属性:masksToBounds,类型选Boolean,值设为true。不过这个方法还是可能受布局时机影响,不如代码方案稳。方案3:用IBDesignable+IBInspectable,还能实时预览
这个方法既能在Storyboard里实时看到圆角效果,运行时也不会有延迟,堪称完美:import UIKit @IBDesignable class RoundedView: UIView { @IBInspectable var cornerRadius: CGFloat = 0 { didSet { updateCornerRadius() } } private func updateCornerRadius() { layer.cornerRadius = cornerRadius layer.masksToBounds = cornerRadius > 0 } override func layoutSubviews() { super.layoutSubviews() // 确保布局变化后圆角依然正确 updateCornerRadius() } }写完之后,你在Storyboard的属性检查器里就能直接看到
cornerRadius的设置项,不用再折腾用户定义运行时属性,运行时还会自动同步布局后的尺寸。
内容的提问来源于stack exchange,提问作者WBuck
相关产品推荐
相关产品推荐

