preface

This article is a Robot’s task article on rounded corners in the AsyncDisplayKit (now Texture) document

Fillet processing

When it comes to rounded corners, many developers insist on using the.cornerradius property of CALayer. Unfortunately, this easy to use attribute greatly increases the performance pressure, and you should only use this attribute when you have no other options. This article will cover:

  • Why shouldn’t it be usedCALayerthe.cornerRadius
  • More high-performance ways to set up rounded corners and when to use them
  • A flow chart that tells you how to choose a rounded corner strategy
  • inTextureExample of setting rounded corners in

Set up the.cornerRadiusAt a great cost

Why is the cornerRadius expensive? This is because using the CALayer’s.cornerRadius property triggers offscreen rendering on the 60FPS screen during scrolling, even if nothing has changed in that area. This means that the GPU must switch the context on every frame, between the synthesis of the entire frame and the additional traversal caused by each use of the cornerRadius. .

It is important that these costs are not shown in the Time Profiler as they affect the work that the CoreAnimation Render Server helps the App do. . This reckless behavior consumes a lot of device performance. On the iPhone 4, 4S, and 5/5C (and similar ipads/iPods), you can see a significant drop in performance. On newer versions of the iPhone, even if you don’t see the direct impact, it reduces memory space, making it easier to drop frames.

High performance Settings for rounded corners

There are only three things to consider when choosing a rounded corner setting policy:

  • Is there any movement under the rounded corners?
  • Is there any movement at the rounded corners?
  • All four corners belong to the same node? And are there any other nodes that intersect in the rounded area?

The node here refers to the basic unit of AsyncDisplayKit (Texture), which is equivalent to UIView in UIKit.

The movement under the rounded corner refers to the movement of everything under the rounded corner layer. For example, when a Collection View cell with rounded corners scrolls over the background layer, the background will move under and out of the rounded corners.

As for the fillet movement, imagine a smaller fillet scroll view containing a large image. When zooming and panning the image inside the Scroll View, the image will move around the rounded corners of the Scroll View.

The above image highlights the movement below the rounded corners in blue and the movement around the rounded corners in orange.

Tip: You can have movement inside a rounded object without going through the rounded corners. The following image shows a highlighted green area with an inner margin equivalent to the scroll View border. When the area is rolled, it does not move at the rounded corners.

Adjusting your design according to the above to eliminate one of the corner moves can make a big difference between using a fast corner technique and using a cornerRadius. .

The final consideration is to determine whether all four corners are at the same node, or whether any child nodes intersect the rounded corner region.

Presynthesized fillet

Rounded corners in the process of the synthesis refers to using bezier path in CGContext/UIGraphicsContext shear content (path. The clip) drawn by the rounded corners. In this case, the corner becomes part of the image itself and is integrated into a single CALayer. There are two types of pre-synthesized fillets.

The best method is to use a pre-synthesized opacity Angle. This is the most efficient method available to achieve alpha-free blending (although this is less important than off-screen rendering), and unfortunately is the least flexible. If the rounded image needs to be moved over a background, the background will need to be solid. One trick is that you can use a textured background or a photo background for pre-composited rounded corners, but generally you’re better off using pre-composited rounded corners with Alpha.

The second approach, which involves pre-synthesized Bezier curve paths with Alpha fillets, is very flexible and should be one of the most commonly used. This approach does produce an Alpha mixing cost for the entire content, and because of the Alpha channel, increases the memory cost by 25% more than the opaque pre-synthesis. But these costs are small for modern devices, and are not in the same order of magnitude as the cost of starting a cornerRadius to render off-screen.

A key limitation of pre-synthesized fillets is that they can only touch one node and cannot intersect any child nodes. If any of these conditions exist, clip Corner must be used.

. Please note that the nodes in the Texture of the cornerRadius have special optimization, only when you use. After shouldRasterizeDescendants will automatically synthesize Angle. It is important to think carefully before enabling rasterization, so do not use this option until you fully understand the concept.

If you want a simple, solid-colored rounded rectangle or circle, Texture provides a handy way to do that. See UIImage + asdialogues. H for a way to create solid-color, resizable images with rounded corners using pre-composited corners that support Alpha and opacity. These are ideal for ASButtonNode backgrounds or placeholders for image nodes.

The cutting Angle

The method is to place four independent opaque corners on the area where the corners need to be rounded. This method is flexible and has good performance. Four separate layers consume less CPU power, one layer for each rounded corner.

The cutting Angle is mainly used in two cases of fillet:

  • A rounded corner that touches more than one node or intersects any child node.
  • Rounded corners on a fixed texture or photo background. Cutting Angle method is tricky, but very useful!

You can use.cornerRadius?

There are very few cases where it is appropriate to use a cornerRadius, including a case where a dynamic area needs to be moved both inside and under the rounded corners. For some animations, this is inevitable. However, in many cases, it is easy to adjust the design to eliminate one of these two moves. One such case is discussed in the rounded Corner Movement section.

It’s not so bad to use a.cornerRadius or use it as an easy implementation when you’re not moving much on screen. However, when there is movement on the screen, even if the area of movement does not contain rounded corners, there is an additional performance burden. For example, having a circular element in the navigation bar with a Scroll view below it will have an effect even if they don’t overlap. Everything on the screen is animated, even if the user is not interacting. In addition, any kind of screen refresh consumes performance on fillet cutting.

Rasterization and layer support

It has been suggested that the.shouldrasterize of a CALayer can improve the cornerRadius property. It’s a choice that’s not well understood, and it’s dangerous. This is used when nothing is causing the layer to re-rasterize (no moving, no clicking to change the color, no moving tableView, etc.). In general, this is discouraged, as it can easily lead to further performance degradation. This can make a meaningful difference to.cornerradius users who don’t have a great application architecture and stick with CALayer (for example, their application is not performing well). However, if you are building your app from scratch, we strongly recommend that you choose one of the better rounded corner strategies described above.

CALayer. ShouldRasterize node and Texture. ShouldRasterizeDescendents has nothing to do. Enabled,. ShouldRasterizeDescendents will stop the child nodes of the actual view and create layer.

Fillet policy flowchart

Use this flowchart to select the best performing strategy to solve the rounded corner problem.

TextureThe support of

The following code illustrates the different ways to use rounded corners in your Texture:

Use the cornerRadius.

var cornerRadius: CGFloat = 20.0

photoImageNode.cornerRoundingType = ASCornerRoundingTypeDefaultSlowCALayer
photoImageNode.cornerRadius = cornerRadius
Copy the code

Use pre-synthesized fillets

var cornerRadius: CGFloat = 20.0

// Use precomposition for rounding corners
photoImageNode.cornerRoundingType = ASCornerRoundingTypePrecomposited
photoImageNode.cornerRadius = cornerRadius
Copy the code

Use the cutting Angle

var cornerRadius: CGFloat = 20.0

photoImageNode.cornerRoundingType = ASCornerRoundingTypeClipping
photoImageNode.backgroundColor = UIColor.white
photoImageNode.cornerRadius = cornerRadius
Copy the code

Using willDisplayNodeContentWithRenderingContext certain areas to set up the rounded corner cutting path

var cornerRadius: CGFloat = 20.0

// Use the screen scale for corner radius to respect content scale
var screenScale: CGFloat = UIScreen.main.scale
photoImageNode.willDisplayNodeContentWithRenderingContext = { context, drawParameters in
    var bounds: CGRect = context.boundingBoxOfClipPath()
    var radius: CGFloat = cornerRadius * screenScale
    var overlay = UIImage.as_resizableRoundedImage(withCornerRadius: radius, cornerColor: UIColor.clear, fill: UIColor.clear)
    overlay.draw(in: bounds)
    UIBezierPath(roundedRect: bounds, cornerRadius: radius).addClip()
}
Copy the code

Use ASImageNode to add rounded corners and borders to the image. This is a good example of adding rounded corners to your avatar.

var cornerRadius: CGFloat = 20.0

photoImageNode.imageModificationBlock = ASImageNodeRoundBorderModificationBlock(5.0.UIColor.orange)
Copy the code