How to set corner radius in iOS
Issue #582
Use View Debugging
Run on device, Xcode -> Debug -> View debugging -> Rendering -> Color blended layer
On Simulator -> Debug -> Color Blended Layer
Corner radius
Okay. Talked to a Core Animation engineer again:
- cornerRadius was deliberately improved in Metal so it could be used everywhere.
- Using a bitmap is WAY heavier in terms of memory and performance.
- CALayer maskLayer is still heavy.
https://developer.apple.com/documentation/quartzcore/calayer/1410818-cornerradius
Setting the radius to a value greater than 0.0 causes the layer to begin drawing rounded corners on its background. By default, the corner radius does not apply to the image in the layer’s contents property; it applies only to the background color and border of the layer. However, setting the masksToBounds property to true causes the content to be clipped to the rounded corners.
https://developer.apple.com/documentation/quartzcore/calayer/1410896-maskstobounds
When the value of this property is true, Core Animation creates an implicit clipping mask that matches the bounds of the layer and includes any corner radius effects. If a value for the mask property is also specified, the two masks are multiplied to get the final mask value.
Mask layer
layer.cornerRadius
, with or without layer.maskedCorners
causes blending
Use mask layer instead of layer.cornerRadius
to avoid blending, but mask causes offscreen rendering
1 | let mask = CAShapeLayer() |
Offscreen rendering
Instruments’ Core Animation Tool has an option called Color Offscreen-Rendered Yellow that will color regions yellow that have been rendered with an offscreen buffer (this option is also available in the Simulator’s Debug menu). Be sure to also check Color Hits Green and Misses Red. Green is for whenever an offscreen buffer is reused, while red is for when it had to be re-created.
Offscreen drawing on the other hand refers to the process of generating bitmap graphics in the background using the CPU before handing them off to the GPU for onscreen rendering. In iOS, offscreen drawing occurs automatically in any of the following cases:
Core Graphics (any class prefixed with CG)
The drawRect() method, even with an empty implementation.
CALayers with a shouldRasterize property set to YES.
CALayers using masks (setMasksToBounds) and dynamic shadows (setShadow).
Any text displayed on screen, including Core Text.
Group opacity (UIViewGroupOpacity).
Instruments
Read more
1 | @abstract Sets the corner rounding method to use on the ASDisplayNode. |
- https://www.hackingwithswift.com/articles/79/how-to-find-and-fix-slow-drawing-using-instruments
- https://stackoverflow.com/questions/35685726/uibezierpath-doesnt-work-in-topright-corner-and-bottomright-corner/43808103
- https://stackoverflow.com/questions/6731545/when-does-a-view-or-layer-require-offscreen-rendering
Generally, on iOS, pixel effects and Quartz / Core Graphics drawing are not hardware accelerated, and most other things are.
The following things are not hardware accelerated, which means that they need to be done in software (offscreen):
Anything done in a drawRect. If your view has a drawRect, even an empty one, the drawing is not done in hardware, and there is a performance penalty.
Any layer with the shouldRasterize property set to YES.
Any layer with a mask or drop shadow.
Text (any kind, including UILabels, CATextLayers, Core Text, etc).
Any drawing you do yourself (either onscreen or offscreen) using a CGContext.
- Make overlay view https://stackoverflow.com/questions/13979935/setting-corner-radius-on-a-cell-kills-uicollectionviews-performance
- http://www.lukeparham.com/blog/2018/3/6/friends-dont-let-friends-render-offscreen
For example, writing your own draw method with Core Graphics means your rendering will technically be done in software (offscreen) as opposed to being hardware accelerated like it is when you use a normal CALayer. This is why manually rendering a UIImage with a CGContext is slower than just assigning the image to a UIImageView.
if layer’s contents is nil or this contents has a transparent background, you just need to set cornerRadius. For UILabel, UITextView and UIButton, you can just set layer’s backgroundColor and cornerRadius to get a rounded corner. Note: UILabel’s backgroundColor is not its layer’s backgroundColor.