性能
掉帧先看图层,不要先怪业务
圆角、阴影、遮罩和光栅化都会把工作丢给 GPU。主线程空着,滚动一样会卡。
Time Profiler 里主线程很闲,手指滑列表仍然一顿一顿。这种时候先看图层,而不是再去拆 JSON。离屏渲染、过大的阴影和每帧都在变的遮罩,账单在 GPU 上。
常见的贵图层
- cornerRadius 加上 masksToBounds,再叠加 shadow,系统往往要先画到屏外再裁。列表里每一行都这样,滑起来就贵。
- 阴影用 shadowPath 指定路径。不指定时,系统要自己算透明区域。
- shouldRasterize 不是万能加速。内容经常变,光栅化缓存一直失效,反而更慢。静态小徽章可以,整行 cell 不要。
圆角头像可以换一条路:图片解码时就切成圆的,或者用一个不裁子图层的绘制。不要为了圆角把整行的内容图层都 masksToBounds。
怎么确认
Instruments 的 Core Animation 可以打开 Color Offscreen-Rendered Yellow、Color Blended Layers。真机上看。模拟器的合成和真机不是同一条管线,黄块只是线索,最后仍以 hitch 毫秒为准。
let badge = UIView()
badge.layer.cornerRadius = 8
badge.layer.shadowColor = UIColor.black.cgColor
badge.layer.shadowOpacity = 0.25
badge.layer.shadowRadius = 6
badge.layer.shadowOffset = CGSize(width: 0, height: 2)
badge.layer.shadowPath = UIBezierPath(roundedRect: badge.bounds, cornerRadius: 8).cgPath
shadowPath 要在布局之后更新,bounds 变了路径也要变。写在 layoutSubviews 里,不要写死一个过期的尺寸。
混合(blending)是另一笔账。半透明叠在会变的内容上,GPU 每次都要混合。能用不透明背景就用不透明,并标上 isOpaque。调试用的半透明遮罩上线前拿掉。